Delegate in Ruby on Rails
Table of contents
What is Delegate
Delegate by the document, which refers to a class method used to easily expose contained objects' public methods as your own. Simply, the concept of delegate is to take some methods and send them off to another object to be processed.
delegate(*methods, to: nil, prefix: nil, allow_nil: nil)
Options:
:to - Specifies the target object
:prefix - Prefixes the new method with the target name or a custom prefix
:allow_nil -if set to true, prevents a NoMethodError to be raised.
Why to use delegate
Law of Demeter or principle of least knowledge is a software design guideline that, according to Wikipedia, is summarized as -
- Each unit should have only limited knowledge about other units: only units “closely” related to the current unit.
- Each unit should only talk to its friends; don’t talk to strangers.
- Only talk to your immediate friends.
delegate method in rails help to enforce this law by exposing only necessary methods of containing objects, thereby, making them more easily accessible.
How to use delegate methods
This may sound a little hard to understand, but let's dive into an example to get under it. Let assume we have two active record models Project and user with the following associations:
class User < ActiveRecord::Base
has_many :projects
end
class Project < ActiveRecord::Base
belongs_to :user
end
Now, if we needed to access the user's objects from projects, it would be like
project = Project.find(3)
project.user.cellphone
project.user.address
Now let's use the delegate method and try to access the same columns from the project model.
class Project < ActiveRecord::Base
belongs_to :user
delegate :address, :cellphone, to: :user
end
We can get the address and cellphone from the project as:
project.cellphone
project.address
Now what if the project model and user model have the same column name? That's where the Prefix argument comes into the play. Lets modify our project model:
class Project < ActiveRecord::Base
belongs_to :user
delegate :name, :address, :cellphone, to: :user, prefix: true
def name
"project"
end
end
If we have the prefix: true, then we can access the project's name and user's name as:
project.name
project.user_name
When we try to access an object that is nil, it will raise an exception. To suppress the error and instead receive the nil response, we can use the allow_nil argument as below:
class Project < ActiveRecord::Base
belongs_to :user
delegate :name, :address, :cellphone, to: :user,
prefix: true, allow_nil: true
end
Project.new.name
will return a nil response.
Let's hope you have got some basic ideas on the delegate method and how to use it.