A Fresh Cup is Mike Gunderloy's software development weblog, covering Ruby on Rails and whatever else I find interesting in the universe of software. I'm a full-time Rails developer and contributor, available for long- or short-term consulting, with solid experience in working as part of a distributed team. If you'd like to hire me, drop me a line. I'm also the author of Rails Rescue Handbook and Rails Freelancing Handbook.

Navigation
« Double Shot #315 | Main | Double Shot #314 »
Sunday
19Oct2008

Coming in Rails 2.2: Delegate Prefixes

Delegates are a useful feature that I haven't seen used in that many Rails codebases - perhaps I've just been looking at the wrong codebases. Active Support makes them available for Modules generally, but the use case I find myself most often exercising is with Active Record classes. Delegates let you take some methods and send them off to another object to be processed.

For example, suppose you have a User class for anyone registered on your site, and a Customer class for those who have actually placed orders:

[sourcecode language='ruby']
class User << ActiveRecord::Base
belongs_to :customer
end

class Customer << ActiveRecord::Base
has_one :user
end
[/sourcecode]

If you're hanging on to a Customer instance, you can get their User information with methods like @customer.user.name and @customer.user.email.

Delegation allows you to simplify this:

[sourcecode language='ruby']
class User << ActiveRecord::Base
belongs_to :customer
end

class Customer << ActiveRecord::Base
has_one :user
delegate :name, :email, :to => :user
end
[/sourcecode]

Now you can refer to @customer.name and @customer.email directly. That's all been around and works in the current release version of Rails.

Delegate prefixes just appeared in edge Rails and will work in Rails 2.2. If you delegate behavior from one class to another, you can now specify a prefix that will be used to identify the delegated methods. For example:

[sourcecode language='ruby']
class User << ActiveRecord::Base
belongs_to :customer
end

class Customer << ActiveRecord::Base
has_one :user
delegate :name, :email, :to => :user, :prefix => true
end
[/sourcecode]

This will produce delegated methods @customer.user_name and @customer.user_email. You can also specify a custom prefix:

[sourcecode language='ruby']
class User << ActiveRecord::Base
belongs_to :customer
end

class Customer << ActiveRecord::Base
has_one :user
delegate :name, :email, :to => :user, :prefix => :account
end
[/sourcecode]

This will produce delegated methods @customer.account_name and @customer.account_email.

Reader Comments (8)

Very nice! Thanks for the heads up.

October 19, 2008 | Unregistered CommenterJonathan Towell

cool, thanks for taking the time to post this. cheers.

October 19, 2008 | Unregistered CommenterDavid

This tip is pretty useful when you have to move attributes from a model to a child model during some refactoring, but you'd like to delay updating each and every view in the application...

Thanks for sharing!

October 20, 2008 | Unregistered CommenterThibaut Barrère

Will this still raise an exception if no association has been found?

October 21, 2008 | Unregistered CommenterIain

Yeah, I'm familiar with the Law of Demeter. I just don't happen to think it's worth setting up as a principle that must never be violated.

December 6, 2008 | Unregistered CommenterMike Gunderloy

Thanks for sharing this. I have used delegate many times, and sometimes this is really needed.

Thanks,

December 14, 2008 | Unregistered CommenterAkhil Bansal

nice post

November 15, 2009 | Unregistered Commenteruma mahesh varma

PostPost a New Comment

Enter your information below to add a new comment.

My response is on my own website »
Author Email (optional):
Author URL (optional):
Post:
 
Some HTML allowed: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <code> <em> <i> <strike> <strong>