Reputation: 522
I have three models, Poem
and Song
and User
.
Users can vote on any number of poems and songs.
One solution would be to make two association models PoemVote
and 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
I can call some_poem_vote.poem
and some_song_vote.song
However, PoemVote
and SongVote
are essentially the same. How do I use single table inheritance to extend the two from one parent Vote
class?
I'm thinking something along these lines:
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
How do I make it work so that I can still call some_poem_vote.poem
but underneath have PoemVotes and SongVotes share one database table? Or is there a better solution for my problem?
Upvotes: 2
Views: 2786
Reputation: 12554
in rails, STI is simple : you just create a type
string column on your votes
table, and rails takes care of the rest. To create the right associations, you can do something like :
class Vote
attr_accessible :user, :votable
belongs_to :user
belongs_to :votable, polymorphic: true
end
...which would require to add a votable_id
and a votable_type
column on your votes
table. Be sure to add
has_many :votes, as: :votable, class_name: 'PoemVote' # or 'SongVote'
on your associated model. However, problem with this approach is that you have to be vigilant and not use Vote
directly to create votes, or you will have votes of the wrong type associated. To enforce this, there is a possible 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
... but i know for sure (i struggled with te same problem) that it opens the door for code horror, as you have to resolve a lot of problems caused by inheritance (scopes behave weirdly, some libs don't manage STI well, etc.).
The question is: do you really need STI ? if your votes behave the same, don't bother using STI, just use a polymorphic belongs_to
, you'll save yourself a lot of headaches.
Upvotes: 4