Self-Referential has_many :through

Hello all.

I am trying to create a self-referential has_many :through. I used the
following site as a guide
http://blog.hasmanythrough.com/articles/2006/04/21/self-referential-through
but it still doesn’t appear to be working. I have two models. Person and
Relationship. A person has many contacts (Which is another person)
through relationships

class Person < ActiveRecord::Base
has_many :relationship
has_many :contacts, :through => :relationship end
end

class Relationship < ActiveRecord::Base
belongs_to :person, :foreign_key => “person_id”
belongs_to :contact, :foreign_key => “contact_id”, :class_name =>
“Person”
end

If I use the code as above then while the relationships appear in the
view the only “Contact” that appears is the Person I am currently
looking at (So the Person “Person A” lists “Person A” as a contact).

If, on the other hand I do the following:

class Person < ActiveRecord::Base
has_many :relationship
has_many :contacts, :through => :relationship end
end

class Relationship < ActiveRecord::Base
belongs_to :person, :foreign_key => “person_id”
belongs_to :contact, :foreign_key => “contact_id”
end

class Contact < ActiveRecord::Base
set_table_name ‘people’
end

It works fine. It appears that setting the :contact to :class_name =>
“Person” screws up the relationship. I would rather avoid defining a
separate “Contact” class and use self-referential but I cannot seem to
do it.

Can anyone offer some advice?

Thanks

RJ

RurouniJones wrote:

I am trying to create a self-referential has_many :through. I used the
following site as a guide
http://blog.hasmanythrough.com/articles/2006/04/21/self-referential-through
but it still doesn’t appear to be working. I have two models. Person and
Relationship. A person has many contacts (Which is another person)
through relationships

class Person < ActiveRecord::Base
has_many :relationship
has_many :contacts, :through => :relationship end
end

class Relationship < ActiveRecord::Base
belongs_to :person, :foreign_key => “person_id”
belongs_to :contact, :foreign_key => “contact_id”, :class_name =>
“Person”
end

If I use the code as above then while the relationships appear in the
view the only “Contact” that appears is the Person I am currently
looking at (So the Person “Person A” lists “Person A” as a contact).

If, on the other hand I do the following:

class Person < ActiveRecord::Base
has_many :relationship
has_many :contacts, :through => :relationship end
end

class Relationship < ActiveRecord::Base
belongs_to :person, :foreign_key => “person_id”
belongs_to :contact, :foreign_key => “contact_id”
end

class Contact < ActiveRecord::Base
set_table_name ‘people’
end

It works fine. It appears that setting the :contact to :class_name =>
“Person” screws up the relationship. I would rather avoid defining a
separate “Contact” class and use self-referential but I cannot seem to
do it.

Can anyone offer some advice?

Take another look at my article and you’ll see you left out a couple
things. One, you are using teh singular :relationship for the has_many
association, and you should be using the plural :relationships. But more
importantly, you don’t have a :class_name option on the :contacts
association. You are also missing the :people association to go the
other direction in the mapping. And you seem to have a spurious “end” in
your Person :contacts declaration. Not sure if those are email
artifiacts or in your real code, so who knows.

You’re pretty close though. Just take another pass to make it work like
described in the article and it should be fine.


Josh S.
http://blog.hasmanythrough.com

I was recently working on this exact same issue, and finally found
another blog with a more descriptive solution (don’t recall where
though). Here’s what I eventually came up with after reading that blog…

class User < ActiveRecord::Base
has_many :users_as_buddies, :foreign_key => “buddy_id”, :class_name =>
“BuddyList”
has_many :users_as_friends, :foreign_key => “friend_id”, :class_name
=> “BuddyList”
has_many :buddies, :through => :users_as_friends
has_many :friends, :through => :users_as_buddies
end

class BuddyList < ActiveRecord::Base
belongs_to :friend, :foreign_key => “friend_id”, :class_name => “User”
belongs_to :buddy, :foreign_key => “buddy_id”, :class_name => “User”
end

buddies; people I’ve added to my buddy list.
friends; people who’ve added ME to THEIR buddy list.

buddies != friends

What happens is, if User A adds User B to their buddy list, User B adds
User C to their own buddy list, and User C adds both User’s A and B to
thier own buddy list, then…

@usera.buddies => UserB
@usera.friends => UserC
@userb.buddies => UserC
@userb.friends => [UserA, UserC]
@userc.buddies => [UserA, UserB]
@userc.friends => UserB

Note that some people would want it so that if User A adds User B to his
buddy list, then User A is automatically on User B’s buddy list. I’m
sure this could be done programatically by adding a mirror image row to
the buddy_lists table every time a buddy list entry is created, but I’m
not sure how to do that strictly through the model relationships.
However, I didn’t want that “feature” for myself, so I wasn’t worried
about it. YMMV.