开发者

Help understanding polymophic associations (rails)

开发者 https://www.devze.com 2023-01-15 03:09 出处:网络
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:

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"

Help understanding polymophic associations (rails)

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.

0

精彩评论

暂无评论...
验证码 换一张
取 消