Delegate vs Forwardable vs SimpleDelegator — Ruby vs Rails

Lakhveer Singh Rajput
4 min readDec 7, 2023

--

In this article, we will be getting through the delegate method in Rails. On the way to learning the delegate, we will also come across the forwardable module and SimpleDecorator Class in Ruby itself. But before all, we should be familiar with the word delegate which means to assign a task to someone.

Delegate — When we take DRY Principle Seriously

Delegate is a class method of the ActiveSupport(means a method of Rails, not Ruby). The delegate will expose the public method of the object to another object. In simple terms, it will give its public behaviors(methods) to the delegated object. Let’s see with an example.

#Catalogue Model
class Catalogue < ApplicationRecord
has_many :orders

def price_name
"#{price} #{name}"
end
end
#Order Model
class Order < ApplicationRecord
belongs_to :catalogue

delegate :name, :price, :price_name, to: :catalogue
end

#console
order = Order.first

# Order Load (0.2ms) SELECT "orders".* FROM "orders" ORDER BY "orders"."id" ASC LIMIT ? [["LIMIT", 1]]
# =>
# <Order:0x00007f8d4cd80bb8
# id: 1,
# total_price: 100,
# total_tax: 10,
# category: "Test1",
# name: "C1",
# catalogue_id: 1,
# created_at: Mon, 04 Dec 2023 07:02:41.995460000 UTC +00:00,
# updated_at: Mon, 04 Dec 2023 07:02:41.995460000 UTC +00:00>

order.price_name
# "100 C1"
order.price
# "100"

In the above example, we have two models Catalogue and Order, where Catalogue had been associated with the Order. We have delegated the method such as name, price, and price_name of the Catalogue to the Order Model. Thus, when we call any of these methods on Order directly, we will get the values without the NoMethodError.

Now this has been done with the help of ActiveSupport. But did Ruby not have any module or anything for the delegation in its core library? The answer is Yes it had. Not just one but two ways for the delegation — Module ‘Forwardable’ and class ‘SimpleDelegator’. Let's have a look at Both of them.

Forwardable — Module to Forward Object Behaviours(Methods)

The Forwardable module of Ruby provides two methods to delegate the object methods to another object — def_delegator and def_delegators. They are the same as the delegate method of ActiveSupport, which exposes the public method of another object to an object. Let’s understand them through an example.

require 'forwardable'
class Person
extend Forwardable

def_delegators :@holding, :person_net_holdings, :person_total_asset_price
#def_delegator :@holding, :person_net_holdings #For Single Method
def initialize(name, total_asset_price, net_holdings)
@holding = Holding.new(total_asset_price, net_holdings)
end
end

class Holding
def initialize(total_asset_price, net_holdings)
@total_asset_price = total_asset_price
@net_holdings = net_holdings
end

def person_net_holdings
"Person Net Holding #{@net_holdings}"
end

def person_total_asset_price
"Person Total Asset Price #{@total_asset_price}"
end
end

person = Person.new("Williams", "$100000", "$10000")


puts person.person_total_asset_price
#Person Total Asset Price $100000
puts person.person_net_holdings
#Person Net Holding $10000

In the above example, there are two classes Person and Holding. Holding had delegated its method(person_total_asset_price and person_net_holdings) to the Person. Now, the person object has access to the methods of the holding object.

Simple Delegator — Make anything out of Me

SimpleDelegator is a class that inherits the Delegator class. Simple Delegator has two methods in it — __getobj__ and __setobj__. This makes the class that inherits Simple Delegator which will clone any object it had been given. Let us see with an example:

require 'delegate'

class Anything < SimpleDelegator
end

class Example
def testing
"We are testing SimpleDelegator"
end
end

array = Anything.new([])
array << "Hey"
array << "I am Array"
puts array
# Hey
# I am Array
string = Anything.new("")
string << "Hey "
string << "I am String"
puts string
# Hey I am String
example = Anything.new(Example.new)
puts example.testing
# We are testing SimpleDelegator

In the above example, we had to form an Anything class which inherits the SimpleDelegator class. The Anything class is now able to take the form of any object it has been passed. As in the above, we had first passed the array, then the string, and again an object of the Example class It simply takes the form of the object provided and then we can perform any method on the Anything object of the object provided.

To be continued

We can have different uses of this delegation technique in Ruby and Rails. Delegation helps in the DRY(Don’t Repeat Yourself) principle to be followed so that the public method of any other object can be accessed and no need to repeat again and again the same code. We will continue again with new topics.

--

--

Lakhveer Singh Rajput
Lakhveer Singh Rajput

Written by Lakhveer Singh Rajput

Ruby on Rails enthusiast, book lover and DevOps explorer. Follow me for insights on coding, book recommendations, and bridging development with operations.🚀📚

Responses (1)