我有三个模型,Poem
和 Song
以及 User
。
用户可以对任意数量的诗歌和歌曲进行投票。
一种解决方案是创建两个关联模型 PoemVote
和 SongVote
class PoemVote
attr_accessible :poem_id, :user_id
belongs_to :poem
belongs_to :user
end
class SongVote
attr_accessible :song_id, :user_id
belongs_to :song
belongs_to :user
end
我可以调用some_poem_vote.poem
和some_song_vote.song
但是,PoemVote
和 SongVote
本质上是相同的。如何使用单表继承从一个父 Vote
类扩展这两个表?
我正在思考以下问题:
class Vote
attr_accessible :resource_id, :user_id
end
class PoemVote < Vote
...not sure what goes here...
end
class SongVote < Vote
...not sure what goes here...
end
如何使其工作,以便我仍然可以调用 some_poem_vote.poem
但在下面让 PoemVotes 和 SongVotes 共享一个数据库表?或者有更好的解决方案来解决我的问题吗?
最佳答案
在 Rails 中,STI 很简单:您只需在 votes
表上创建一个 type
字符串列,rails 就会处理其余的事情。要创建正确的关联,您可以执行以下操作:
class Vote
attr_accessible :user, :votable
belongs_to :user
belongs_to :votable, polymorphic: true
end
...这需要在您的 votes
表中添加 votable_id
和 votable_type
列。请务必添加
has_many :votes, as: :votable, class_name: 'PoemVote' # or 'SongVote'
在您的关联模型上。然而,这种方法的问题在于,您必须保持警惕,不要直接使用 Vote
来创建投票,否则您将获得错误类型的关联投票。为了强制执行此操作,有一个可能的 hack :
class Vote
attr_accessible :resource_id, :user_id
def self.inherited( subclass )
super( subclass )
subclass.send :belongs_to, :votable,
class: "#{subclass.name.gsub('Vote','')}"
end
end
...但我确信(我在同样的问题上苦苦挣扎)它为代码恐怖打开了大门,因为你必须解决由继承引起的很多问题(作用域表现得很奇怪,有些库没有管理好性传播感染等)。
问题是:您真的需要性传播感染吗?如果您的投票行为相同,请不要使用 STI,只需使用多态的 belongs_to
,您会省去很多麻烦。
关于ruby-on-rails - Rails - 单表继承中的多态性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13668040/