# Bidirectionnal relation

**URL:** <https://www.ruby-forum.com/t/bidirectionnal-relation/110273>\
**Category:** Ruby\
**Created:** [July 24, 2007, 8:39pm UTC](https://www.ruby-forum.com/t/bidirectionnal-relation/110273 "2007-07-24T20:39:45Z")\
**Posts on this page:** 6\
**Page:** 1

<div class="post-metadata">

**Author:** ![dohzya](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/d/bb73d2/32.png) [@dohzya](https://www.ruby-forum.com/u/dohzya)\
**Post date:** [July 24, 2007, 8:39pm UTC](https://www.ruby-forum.com/t/bidirectionnal-relation/110273/1 "2007-07-24T20:39:45Z")

</div>

Hi everyone,  
I have a problem with bidirectional relations : how to implements it ?

## I can’t implements it with 2 relations without synchronize them :

# no synchronization

class Entity  
attr\_accessor :mother  
attr\_reader :daughters  
def initialize  
@daughters = []  
end  
end

## a = Entity.new b = Entity.new a.mother = b puts (b.daughters.include? a) # false a.daughters \<\< b puts (b.mother == a) # false

too bad…

## Try with a simple synchronization :

# simple synchronization

class Entity  
attr\_reader :mother, :daughters  
def initialize  
@daughters = []  
end  
def mother= m  
@mother.daughters.delete self unless @mother.nil?  
@mother = m  
@mother.daughters \<\< self unless @mother.nil?  
end  
def add\_daughter d  
unless d.nil?  
@daughters \<\< d  
d.mother = self  
end  
end  
end

## a = Entity.new b = Entity.new a.mother = b puts (b.daughters.include? a) # true a.daughters \<\< b # it’s possible so why not use it ? puts (b.mother == a) # false

ok for some operations, but not exhaustive.

## The problem seems to come from @daughters which is a simple Array. Let’s fix it :

# better synchronization

class Entity  
attr\_reader :mother, :daughters  
def initialize  
@daughters = []  
class \<\< @daughters  
attr\_accessor :mother  
alias **old\_add** \<\<  
def \<\< d, recc=false  
**old\_add** d  
d.mother = @mother unless recc  
end  
alias **old\_delete** delete  
def delete d  
if include? d  
d.mother = nil  
**old\_delete** d  
end  
end  
end  
@daughters.mother = self  
end  
def mother= m  
@mother.daughters.delete self unless @mother.nil?  
@mother = m  
@mother.daughters.\<\<(self, true) unless @mother.nil?  
end  
def add\_daughter d  
unless d.nil?  
@daughters \<\< d  
d.mother = self  
end  
end  
end

## a = Entity.new b = Entity.new a.mother = b puts (b.daughters.include? a) # true a.daughters \<\< b puts (b.mother == a) # true

ok it works (I think), but I need to redefine all methods from  
@daughters…

26 lines more than the first (and natural) solution, for a really simple  
problem… I don’t think I’ll often use it.

I tried to implement a solution with a real relation, but I had too many  
problems.

If anyone has a suggestion (solution or link or anything) to implement  
transparent bidirectional relation… 🙂  
Thanks !

---

<div class="post-metadata">

**Author:** ![dohzya](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/d/bb73d2/32.png) [@dohzya](https://www.ruby-forum.com/u/dohzya)\
**Post date:** [July 24, 2007, 9:29pm UTC](https://www.ruby-forum.com/t/bidirectionnal-relation/110273/2 "2007-07-24T21:29:55Z")

</div>

dohzya wrote:

> Hi everyone,  
> I have a problem with bidirectional relations : how to implements it ?

How about:  
class Female  
attr\_accessor :mother  
def initialize( name )  
@name = name  
@daughters = []  
end  
def daughters  
@daughters.dup.freeze  
end  
def mother=( mom )  
@mother = mom  
unless mom.daughters.include?( self )  
mom.add\_daughter( self )  
end  
end  
def add\_daughter( girl )  
@daughters \<\< girl unless @daughters.include?( girl )  
girl.mother = self  
end  
def inspect  
“\<Female ‘#{@name}’\>”  
end  
end

a = Female.new( ‘Strami’ )  
b = Female.new( ‘Lisa’ )  
c = Female.new( ‘Imogen’ )

b.mother = a  
p a.daughters.include?( b )  
#=\> true

b.daughters \<\< c  
#=\> Error: can’t modify frozen array (TypeError)

b.add\_daughter c

p a.daughters  
#=\> [\<Female ‘Lisa’\>]

p b.daughters  
#=\> [\<Female ‘Imogen’\>]

p c.mother  
#=\> \<Female ‘Lisa’\>

---

<div class="post-metadata">

**Author:** ![dohzya](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/d/bb73d2/32.png) [@dohzya](https://www.ruby-forum.com/u/dohzya)\
**Post date:** [July 25, 2007, 6:26pm UTC](https://www.ruby-forum.com/t/bidirectionnal-relation/110273/3 "2007-07-25T18:26:22Z")

</div>

2007/7/24, dohzya [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid):

> I have a problem with bidirectional relations : how to implements it ?  
> (…)  
> If anyone has a suggestion (solution or link or anything) to implement  
> transparent bidirectional relation… 🙂

Hi Etienne,

in ruby-talk:121602 I posted a little library to implement this.  
Here’s your example:

require “relation”

class Entity  
end

Relation.new Entity, :one, :mother, Entity, :many, :daughters

a = Entity.new  
b = Entity.new

a.mother = b  
puts(b.daughters.include?(a)) # =\> true

a.daughters \<\< b  
puts(b.mother == a) # =\> true

If you find nothing else maybe I should create my first gem…

Regards,  
Pit

---

<div class="post-metadata">

**Author:** ![dohzya](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/d/bb73d2/32.png) [@dohzya](https://www.ruby-forum.com/u/dohzya)\
**Post date:** [July 25, 2007, 8:05pm UTC](https://www.ruby-forum.com/t/bidirectionnal-relation/110273/4 "2007-07-25T20:05:20Z")

</div>

Le jeudi 26 juillet 2007 à 01:25 +0900, Pit C. a écrit :

> a.mother = b

Why find again ? it’s exactly what I want !

I wait for your gem, thanks 🙂

---

<div class="post-metadata">

**Author:** ![dohzya](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/d/bb73d2/32.png) [@dohzya](https://www.ruby-forum.com/u/dohzya)\
**Post date:** [July 25, 2007, 8:56pm UTC](https://www.ruby-forum.com/t/bidirectionnal-relation/110273/5 "2007-07-25T20:56:42Z")

</div>

Le jeudi 26 juillet 2007 à 01:25 +0900, Pit C. a écrit :

> 2007/7/24, dohzya [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid):
> 
> > I have a problem with bidirectional relations : how to implements  
> > it ?  
> > (…)  
> > If anyone has a suggestion (solution or link or anything) to  
> > implement  
> > end  
> > puts(b.mother == a) # =\> true
> 
> If you find nothing else maybe I should create my first gem…
> 
> Regards,  
> Pit

Why find again ? it’s exactly what I want !

I wait for your gem, thanks 🙂

---

<div class="post-metadata">

**Author:** ![dohzya](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/d/bb73d2/32.png) [@dohzya](https://www.ruby-forum.com/u/dohzya)\
**Post date:** [July 26, 2007, 10:08am UTC](https://www.ruby-forum.com/t/bidirectionnal-relation/110273/6 "2007-07-26T10:08:44Z")

</div>

Le jeudi 26 juillet 2007 à 01:25 +0900, Pit C. a écrit :

> 2007/7/24, dohzya [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid):
> 
> > I have a problem with bidirectional relations : how to implements  
> > it ?  
> > (…)  
> > If anyone has a suggestion (solution or link or anything) to  
> > implement  
> > end  
> > puts(b.mother == a) # =\> true
> 
> If you find nothing else maybe I should create my first gem…
> 
> Regards,  
> Pit

Why find again ? it’s exactly what I want !

I wait for your gem, thanks 🙂

(and I hate my mail client…)
