# \[newbie\] Symmetric relationships

**URL:** <https://www.ruby-forum.com/t/newbie-symmetric-relationships/71412>\
**Category:** Rails\
**Created:** [October 8, 2006, 9:52am UTC](https://www.ruby-forum.com/t/newbie-symmetric-relationships/71412 "2006-10-08T09:52:11Z")\
**Posts on this page:** 4\
**Page:** 1

<div class="post-metadata">

**Author:** ![AnalogKid](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/a/958977/32.png) [@AnalogKid](https://www.ruby-forum.com/u/AnalogKid)\
**Post date:** [October 8, 2006, 9:52am UTC](https://www.ruby-forum.com/t/newbie-symmetric-relationships/71412/1 "2006-10-08T09:52:11Z")

</div>

This is my first shot at using Rails… How does one establish symmetric  
relationships? I’m building a web application where family  
relationships between members is useful to know. I’m not sure how to  
get the joins to work though…

I have a table of Members and I want to capture, for example, spousal  
relationships. The problem I’m running into is that both sides of the  
relationship will point back to the ‘members’ table, but must have  
different column names.

class CreateRelationships \< ActiveRecord::Migration  
def self.up  
create\_table :relationships do |t|  
t.column :member\_id, :integer  
t.column :member2\_id, :integer  
#preset tags such as “spousal”, “parental”, “other”  
t.column :type, :string, :limit =\> 15  
#type to be used for “other”  
t.column :type\_for\_other, :string, :limit =\> 50  
end  
end

def self.down  
drop\_table :relationships  
end  
end

Using a ‘has\_many :relations, :through =\> :relationships’ link seems  
appropriate, but I’m not sure how to key it to both columns.

class Member \< ActiveRecord::Base  
has\_many :relations, :through =\> :relationships  
end

Is this a job for the :source attribute?

---

<div class="post-metadata">

**Author:** ![AnalogKid](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/a/958977/32.png) [@AnalogKid](https://www.ruby-forum.com/u/AnalogKid)\
**Post date:** [October 9, 2006, 1:52am UTC](https://www.ruby-forum.com/t/newbie-symmetric-relationships/71412/2 "2006-10-09T01:52:39Z")

</div>

On 10/8/06, AnalogKid [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) wrote:

> different column names.  
> end
> 
> >

I think the proper way of modelling this kind of relationship is to have  
two  
entries in the Relationships table. Otherwise, the semantics of the  
fields  
change depending on which way you are looking at the relationship.

So rather than having mem,ber and member2, you would have  
relationship\_owner  
and related\_person, where your model class should take care of creating  
both  
relationship entries in a add\_relationship method or similar. This will  
also  
make your queries a lot easier. For example, for a father/son  
relationship,  
you will have:

relationship\_owner related\_person relationship  
Daddy Bob Little Joe Son  
Little Joe Daddy Bob Father

When you are querying for everybody who is a son, you only need to look  
for  
a “Son” relationship, rather than having endless conditions on  
(member=some\_id and relationship=‘Son’) OR (member\_2=some\_id and  
relationship=‘Father’)

Cheers,  
Max

---

<div class="post-metadata">

**Author:** ![AnalogKid](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/a/958977/32.png) [@AnalogKid](https://www.ruby-forum.com/u/AnalogKid)\
**Post date:** [October 9, 2006, 5:28am UTC](https://www.ruby-forum.com/t/newbie-symmetric-relationships/71412/3 "2006-10-09T05:28:52Z")

</div>

I’m facing a similar problem except that any given individual can have  
many  
relationships. For example, Daddy Bob may be Little Joe’s father. At the  
same time, he might also be Suzy Q’s husband and Little O. Annie’s  
employer.

How would you model that kind of networked relationship?

(sorry to hijack this thread, but I’m guessing this is an issue others  
may  
have as well.)

Max M.-3 wrote:

> relationship entries in a add\_relationship method or similar. This will  
> for  
> a “Son” relationship, rather than having endless conditions on  
> (member=some\_id and relationship=‘Son’) OR (member\_2=some\_id and  
> relationship=‘Father’)

–  
View this message in context:  
[http://www.nabble.com/-newbie--Symmetric-relationships-tf2403812.html#a6711119](http://www.nabble.com/-newbie--Symmetric-relationships-tf2403812.html#a6711119)  
Sent from the RubyOnRails Users mailing list archive at [Nabble.com](http://Nabble.com).

---

<div class="post-metadata">

**Author:** ![AnalogKid](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/a/958977/32.png) [@AnalogKid](https://www.ruby-forum.com/u/AnalogKid)\
**Post date:** [October 9, 2006, 6:04am UTC](https://www.ruby-forum.com/t/newbie-symmetric-relationships/71412/4 "2006-10-09T06:04:53Z")

</div>

On 10/9/06, s.ross [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) wrote:

> (sorry to hijack this thread, but I’m guessing this is an issue others may  
> have as well.)
> 
> \>

This layout for a relationship table models a many-to-many relationship  
between entries for people. There hsould not be anything else you need  
to  
do, except add more rows:

relationship\_owner related\_person relationship  
Daddy Bob Little Joe Son  
Little Joe Daddy Bob Father  
Daddy Bob Annie Wife  
Annie Daddy Bob Husband

Just make sure that your model creteas the appropriate reverse  
relationship,  
for example:

class Person \< ActiveRecord::Base

reverse\_relationships = [  
:Child=\>:Parent,  
:Parent=\>:Child,  
:Husband=\>:Wife,  
:Wife=\>Husband,  
:Employer=\>Employee,  
:Employee=\>Employer  
]

def relate\_to(person, relationship)  
r1 = Relationship.create do |r|  
r.owner = this  
r.related\_person = person  
r.relationship = relationship  
end

```
r2 = Relationship.create do |r|
   r.owner = person
   r.related_person = this
   r.relationship = reverse_relationships[relationship.intern].to_s
end

```

end

end

Note that this does not make a distinction between Son/Daughter or  
Mother/Father.

If you have your has\_many :through set up right, you can then use  
Person.find(1).relationships.

You can even use association extensions:

has\_many :related\_people, :through=\>:relationship do  
def relation(type\_of\_relationship)  
find(:all, :conditions=\>[ ‘relationship\_type=?’,  
type\_of\_relationship ]  
end  
end

You can then do:

dad = Person.find(1)  
children = dad.related\_people.relation(‘Child’)

As the association extension automatically sets the scope to the parent  
relationship (parent and relationship here are in relational database  
terms).

Cheers,  
Max
