Pros/cons of doubling up in Self-Referential has_many via :t


#1

Relative newbie so would welcome comments re structure of a
self-referential relationship I’ve got.

It’s started off similar to the Person HABTM friends in the Rails
recipes books (working fine), but I needed to turn the join table into a
full-blown model as I wanted to add attributes to it. Few tricky bits
dealing with the new :through structure and understanding how :scope
worked but got there OK in the end with the help of the console and lots
of checking of the log.

Now, to the question. The relationship is a reflexive one – i.e. if
person A has a relationship (of type i) with person B, then person B has
a relationship (of type i) with person A. In Rails Recipes (and in my
original HABTM setup), this was done by automatically adding a reverse
row to the relationships table using :after_add (and removing it with
:after_remove).

Downside is that if the table has attributes (relationship_type, notes
on relationship) this starts to get a bit messy, meaning that every time
one is updated the reverse must be too. I could wrap this up in a
transaction, but somehow it seems a bit inelegant.

The other way – which is how I’ve done it – is to leave the
relationship with a single entry in the relationship table and add an
instance method to the model which bundles up those people who have who
have a relationship with A and all those who A has a relationship. Given
that I also want to get the relationship id, the notes and the
relationshiptype, I’ve got something like this (sorry for all the
relatee and relation_tos, etc):

def allrelations
ar1 = self.relation_froms.find(:all, :include => :relator).collect
{|c| {“id” =>c.id, “notes” =>c.notes, “reltype” => c.reltype, “person”
=>c.relator} }
ar2 = self.relation_tos.find(:all, :include => :relatee).collect
{|d| {“id” =>d.id, “notes” =>d.notes, “reltype” => c.reltype, “person”"
=>d.relatee} }
ar=ar1+ar2
end

I can then loop through them in the view, with something like this:
<% for r in @person.allrelations %>
<%= h(r[“person”].fullname) %> (<%= h(r[“reltype”]) %>) <%=
h(r[“notes”]) %>

<% end %>

I’d welcome some comments on this (as I said, pretty noobish) – am I
better off sticking with the original write-twice system? Will the
allrelations method get too heavy as the tables grow in size? Does the
idea (and/or code) suck?

Thanks in advance

Chris T