Glad You're Ready. Let's Get Started!

Let us know how we can contact you.

Thank you!

We'll respond shortly.

Rails' delegates are even more useful than I knew

File this under “things I wish I’d known about years ago”…

Do you use delegate in Rails? It’s a great way to avoid Law of Demeter violations. Let’s say you’re modeling people, who belong to households:

class Person
  belongs_to :household
  delegate :address, to: household

class Household
  # has a string attribute 'address'

Now we can get the address of a Person with the Demeter-friendly
person.address, rather than the trainwreck person.household.address.
When we decide suddenly that a person sometimes needs to override its
household’s address, we can change this to:

class Person
  belongs_to :household

  def address
    overriding_address || household.address

and we don’t have to change any code which refers to person.address.

But! What about this?

class Person
  # has a string attribute 'name'

class Business
  belongs_to :owner, class_name: 'Person'

How do we get the name of a business’s owner? We could say, but that’s a Demeter violation. We could delegate,
but then we’d have, which would be wrong. Luckily, the
authors of delegate have thought of this:

class Business
  belongs_to :owner, class_name: 'Person'
  delegate :name, to: :owner, prefix: true

The prefix: true option gives us business.owner_name, which is much
better. You can also specify a custom prefix instead of true.

After doing this manually by defining methods for years, I feel silly to
learn that the prefix option has been around since 2008!

  1. Joe Van Dyk says:

    Using delegation like this always bugs me.

    Say you need to access a business owner’s email address, phone number, and address.

    Are you going to define delegators for each of those methods in the Business model?

  2. Peter Jaros says:

    It depends: why are you asking for those things?

    If you’re interested in properties of the business (say, you’re in businesses/show.html.haml), and one of those properties is the name of the business owner, you’d want to ask the business for it’s owner name. The business is responsible for figuring out where to look for that name.

    But, maybe you’re showing the owner as a Person box on the business’s page. Then your business/show template would `render business.owner`, which will render the partial `people/person`. That partial will have a local `person`, and since `person` is this partial’s friend, so it’s allowed to ask it for its name.

    If you’re looking for all three of those properties (email address, phone number, and address), you’re probably doing something more like the latter than the former. Here, the Law of Demeter is telling you not to add delegation but to use a partial.

  3. […] above code would make them inaccessible, but that’s what you get with contrived examples. See this post on the Pivotal Labs’ blog for a […]

  4. Mitch Langlois says:

    Great explanation. Thank you :)

  5. Andrew says:

    Could you achieve a better performance by _not_ delegating, and instead, writing a SQL JOIN where possible? ie: a method called household on your Person class that just executes SQL?

Post a Comment

Your Information (Name required. Email address will not be displayed with comment.)

* Copy This Password *

* Type Or Paste Password Here *