2

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

一种解决方案是制作两个关联模型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.poem我可以打电话some_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 共享一个数据库表?或者我的问题有更好的解决方案吗?

4

1 回答 1

4

在 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

...但我确定(我在同样的问题上苦苦挣扎)它为代码恐怖打开了大门,因为你必须解决很多由继承引起的问题(作用域表现得很奇怪,一些库不能很好地管理 STI , ETC。)。

问题是:你真的需要STI 吗?如果您的投票表现相同,请不要使用 STI,只需使用 polymorphic belongs_to,您将为自己省去很多麻烦。

于 2012-12-02T10:00:49.597 回答