Chris T
2006-Apr-17 16:35 UTC
[Rails] Pros/cons of doubling up in Self-Referential has_many via :through
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"]) %><br /> <% 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