I know there are plenty of resources on this but I'm having a tough time relating any of them to my situation so I was hoping someone could help me clarify how this works:
Basically I have a model Action
, (which gets created anytime a user does something that affects another user, like commenting on their article or voting on someones photo, for example), these actions will be listed in the users dashboard page as all the actions that have taken place that relate to them, like a stream... sort of like Github's "News Feed"
I've decided to go with creating a polymorphic association, here is what my model looks like:
class Action < ActiveRecord::Base
belongs_to :instigator, :polymorphic => true
belongs_to :victim, :polymorphic => true
end
I used instigator and victim because anyone can create these actions, which in turn always affect another user, here is my User
model
class User < ActiveRecord::Base
has_many :actions, :as => :instigator
has_many :actions, :as => :victim
end
And this is where I think I'm going wrong, because ultimately I want to have a query which when I run something like User.find(1).actions
to actually return all the instances in which the user is both an instigator
or a victim
, I think I can't have both of those have_many
's in there, because when used like this I only get the instances where the user is开发者_Go百科 the victim
.
Here is my migration:
create_table :actions do |t|
t.references :instigator, :polymorphic => true
t.references :victim, :polymorphic => true
t.string :action_performed
t.references :resource, :polymorphic => true
t.timestamps
end
Thanks for any help, I always love the great suggestions and help the SO community gives.
This reminds of classic Friendship model problem. Polymorphic association is besides the point.
Rails version agnostic solution:
class User < ActiveRecord::Base
has_many :instigator_actions, :class_name => "Action", :as => :instigator
has_many :victim_actions, :class_name => "Action", :as => :victim
has_many :actions, :finder_sql => '
SELECT a.*
FROM actions a
WHERE (a.instigator_type = "User" AND instigator_id = #{id}) OR
(a.victim_type = "User" AND victim_id = #{id})'
end
While creating the Actions create them using one of the first two associations.
u1.instigator_actions.create(:victim => u2)
OR
u1.victim_actions.create(:instigator => u2)
At the same time you can get a list of actions associated with an user using the actions
association.
u1.actions
Firstly I suggest you use roles through Single table Inheritance. In your user table , you can have a type column which identifies someone as an instigator or as a victim. (Of course if someone is both , he will have 2 rows , so you will have to make sure you dont have the name as the primary key.)
So now you have a more structured layout. Coming to the polymorphism problem,try using a different interface. As in,
class Action < ActiveRecord::Base
belongs_to :actionable, :polymorphic => true
end
actionable need not be a separate class. Its just a name given to the interface.Like wise on the other side of the association.
The Rails Way by Obie Fernandez gives you a clear picture on this, so you can refer it for more dope on polymorphic associations.
精彩评论