Delegation and Demeter in Rails

Friday, December 22

I recently discovered this little nugget. After reading Jay Fields’ post on the topic of decoupling and the law of Demeter I’ve been using Ruby’s Forwardable module to accomplish basic delegation tasks. Alas, Rails (via ActiveSupport) has a really handy method that encapsulates this pattern quite nicely: a class method called delegate

Consider a Person class with an associated Profile. Pretend the Profile class has an associated collection called favorite_books.


class Person < ActiveRecord::Base
  has_one :profile
end

class Profile < ActiveRecord::Base
  belongs_to :person
  has_many :favorite_books
end

If you wanted to see a Person’s favorite books collection, you’d have to go through profile:

Person.find(:first).profile.favorite_books

Which of course would throw a no method error if profile returned Nil. Using delegation, we can do this:


class Person < ActiveRecord::Base
  has_one :profile
  delegate :favorite_books, :to => :profile
end

Now we can say:

Person.find(:first).favorite_books

and not have to worry whether the profile exists or not, thus alleviating us from having to write an accessor in Person like def favorite_books() profile ? profile.books : nil; end.

Very nice indeed.