Redundant Bidirectional Relationships in Rails Suck

2008-04-09 20:00:00 -0400


Update 06-JUN-2008: This plugin now includes acts_as_union, and we moved the repository to GitHub.

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.