Rails - 单表继承中的多态

时间:2012-12-02 09:37:04

标签: ruby-on-rails polymorphism single-table-inheritance

我有三个模型,PoemSong以及User。 用户可以对任意数量的诗歌和歌曲进行投票。

一种解决方案是制作两个关联模型PoemVoteSongVote

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.poemsome_song_vote.song

但是,PoemVoteSongVote基本相同。如何使用单表继承从一个父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共享一个数据库表?或者我的问题有更好的解决方案吗?

1 个答案:

答案 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_typevotes列。一定要添加

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,你就会省去很多麻烦。