我有三个模型,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共享一个数据库表?或者我的问题有更好的解决方案吗?
答案 0 :(得分:3)
在rails中,STI很简单:您只需在type
表上创建一个votes
字符串列,rails就可以完成剩下的工作。要创建正确的关联,您可以执行以下操作:
class Vote
attr_accessible :user, :votable
belongs_to :user
belongs_to :votable, polymorphic: true
end
...需要在votable_id
表格中添加votable_type
和votes
列。一定要添加
has_many :votes, as: :votable, class_name: 'PoemVote' # or 'SongVote'
关联模型上的。但是,这种方法的问题在于您必须保持警惕,不要直接使用Vote
来创建投票,否则您将获得错误类型的投票。要强制执行此操作,可能存在黑客攻击:
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
...但我肯定知道(我在同样的问题上挣扎)它为代码恐怖打开了大门,因为你必须解决由继承引起的很多问题(范围很奇怪,一些libs没有很好地管理STI等。)
问题是:你真的需要 STI吗?如果你的投票表现相同,不要打扰使用STI,只需使用多态belongs_to
,你就会省去很多麻烦。