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:
class User << ActiveRecord::Base belongs_to :customer end class Customer << ActiveRecord::Base has_one :user end
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:
class User << ActiveRecord::Base belongs_to :customer end class Customer << ActiveRecord::Base has_one :user delegate :name, :email, :to => :user end
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:
class User << ActiveRecord::Base belongs_to :customer end class Customer << ActiveRecord::Base has_one :user delegate :name, :email, :to => :user, :prefix => true end
This will produce delegated methods @customer.user_name and @customer.user_email. You can also specify a custom prefix:
class User << ActiveRecord::Base belongs_to :customer end class Customer << ActiveRecord::Base has_one :user delegate :name, :email, :to => :user, :prefix => :account end
This will produce delegated methods @customer.account_name and @customer.account_email.


8 comments
Comments feed for this article
October 19, 2008 at 12:13 pm
Jonathan Towell
Very nice! Thanks for the heads up.
October 19, 2008 at 11:20 pm
David
cool, thanks for taking the time to post this. cheers.
October 20, 2008 at 7:01 am
Thibaut Barrère
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 21, 2008 at 12:50 pm
Iain
Will this still raise an exception if no association has been found?
November 21, 2008 at 5:33 am
Anonymous
what is the interest of account_name vs account.name, less db request ? Does this mean that you have an include automaticly exacuted each time you retrieve a customer ?
December 6, 2008 at 12:43 pm
Alexandre
See here… http://en.wikipedia.org/wiki/Law_of_Demeter
December 6, 2008 at 12:57 pm
Mike Gunderloy
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 14, 2008 at 6:17 am
Akhil Bansal
Thanks for sharing this. I have used delegate many times, and sometimes this is really needed.
Thanks,