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 software developer: most of my time in recent years has been spent writing Rails, though I've dabbled in many other things and like most people who have been writing code for decades I can learn new stuff as needed.

Currently I'm employed as the Vice President of Engineering at Faria Education Group. If you're interested in working with me, we're often hiring smart developers. Drop me a comment if you're interested or email MikeG1 [at] larkfarm.com.

Navigation
« Double Shot #315 | Main | Double Shot #314 »
Sunday
Oct192008

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.
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>