2012-12-02 79 views
2

我有三個模型,PoemSongUser。 用戶可以對任意數量的詩歌和歌曲進行投票。Rails - 單表繼承中的多態性

一種解決方案是使兩個關聯模型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共享一個數據庫表?或者有更好的解決方案來解決我的問題?

回答

3

在導軌中,STI非常簡單:您只需在votes表上創建一個type字符串列,其餘部分由導軌完成。要建立正確的關聯,你可以這樣做:

class Vote 
    attr_accessible :user, :votable 
    belongs_to :user 
    belongs_to :votable, polymorphic: true 
end 

...這將需要對您的votes表中添加votable_idvotable_type列。請務必在您的關聯型號上添加

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 

...但我肯定知道(我掙扎與TE同樣的問題),它打開了代碼恐怖的大門,因爲你必須解決很多繼承導致的問題(範圍行爲異常,某些庫不能很好地管理STI等)。

問題是:你真的需要 STI?如果您的投票表現相同,請不要打擾使用STI,只需使用多態性belongs_to,您將爲自己節省很多頭痛。

+0

得到它的工作 - 謝謝:) 用你的投票例子, '類PoemVote <投票 belongs_to的:詩,CLASS_NAME: '詩',foreign_key: 'votable_id' end' – wyclin