I’d like to create a self referencing relation in rails. I have a Person model, and the person should have masters and pupils with same Person object.
So far I tried:
class Person <ActiveRecord::Base
has_many :relationships, :dependent => :destroy
has_many :masters, :through => :relationships, :conditions => "status='master'"
has_many :pupils, :through => :relationships, :conditions => "status='pupil'"
has_many :inverse_relationships, :class_name => "Relationship",
:foreign_key => "related_id"
has_many :inverse_masters, :through => :inverse_relationships,
:source => :person, :conditions => "status='master'"
has_many :inverse_pupils, :through => :inverse_relationships,
:source => :person, :conditions => "status='pupil'"
end
class Relationship < ActiveRecord::Base
belongs_to :person
belongs_to :master, :class_name => "Person", :foreign_key => 'related_id'
belongs_to :pupil, :class_name => "Person", :foreign_key => 'related_id'
end
It seems to work when I am trying to select:
@a = Person.find(:first)
@a.masters
but when I try to do a push into masters, it saves the relationship without the status set to master. It saves null instead. Is there an easy way to save status=master when I push into masters and status=pupil when I push into pupils?
Thanks
To make it short the solution is: association callbacks (more here under the Association Callback section: http://railsapi.com/doc/rails-v3.0.0/classes/ActiveRecord/Associations/ClassMethods.html)
To be a little more detailed I have adapted your example a little bit, but basically the structure is the same, here is the code:
The RelationShip model contains a type column which is the equivalent of your status column, but type is nicer if I later want to do an STI and declare MasterPupil/PupilMaster relationship models.
RelationShip also has a set_type before_validation that will set the type to OpenRelationship which should be temporary before the after_add callback defined in the Person model in each association will set things clear (and set either a MasterPupil or PupilMaster type)
and now: