A better-late-than-never announcement: we released a Rails plugin a while ago that implements a better, DRYer way to roll network relationships using ActiveRecord. It's called, acts_as_network and it now updated to support Rails 2.0.
So why is this such a problem? It may not be immediately apparent, but the short answer is that these types of relationships usually require 2 redundant rows of storage in your database. Take a social network relationship: one record might say that Jack is Jill's friend, but a separate row must be present to say Jill is Jack's friend.
acts_as_network does away with this nonsense, and lets you say implicitly that If Jack is Jill's friend then Jill is Jack's friend. Or, in Ruby
# Jane invites Jack to be friends
invite = Invite.create(:person => jane, :person_target => jack, :message => "let's be friends!")
jane.friends.include?(jack) => false # Jack is not yet Jane's friend
jack.friends.include?(jane) => false # Jane is not yet Jack's friend either
invite.is_accepted = true # Now Jack accepts the invite
invite.save and jane.reload and jack.reload
jane.friends.include?(jack) => true # Jack is Janes friend now
jack.friends.include?(jane) => true # Jane is also Jacks friend
The syntax is clean, and it stores only one row in your HABTM table. Online Documentation available or install/upgrade the plugin:
% script/plugin install git://github.com/sjlombardo/acts_as_network.git
% rake doc:plugins
Much thanks to Maurycy for submitting patches to AAN!
Note: for a more in depth look at the acts_as_network syntax and usage please check out the original release page.