Delegate Method

2 Min. Read
Jan 12, 2020

Delegate method in ruby

There a manner with which we can deflect a work that has been provided to an object to another object. This is known as delegation of method, which is used to hide implementation details as well as not raise an error whenever an object is asked to do something which isn’t natively defined in itself.

Let us look at an example. Let us assume there’s a Building class and a subsequent Door class that is initialized when an object of Building is created.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class Building
  def initialize
    @door = Door.new
  end
end

class Door
  def initialize
    @state = "open"
  end
  def close
    @state = "close"
  end
  def open
    @state = 'open'
  end
end

building = Building.new

Now, as we can tell, a call to the method close from the building object building.close will raise a NoMethodError. We can delegate the method to Door class, as it contains the method open that we want to call. Let’s open the class Building and patch in a method:

1
2
3
4
5
class Building
  def close
    @door.close
  end
end

Now, calling the method close, Building.close produces desired output. Here, the method close for Building class is a delegator method.

Different approaches to delegating methods

  • Using forwardable module
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
require 'forwardable'

class Building extend Forwardable
  def_delegators :@door, :close, :open
  def initialize
    @door = Door.new
end

class Door
  def initialize
    @state = "open"
  end
  def close
    @state = "close"
  end
  def open
    @state = 'open'
  end
end

building = Building.new
building.close

Here, the delegator method takes in arguments,namely the object we are delegating to and the delegate methods

  • Using method missing eg: from class reach to reachable
1
2
3
4
5
6
7
8
9
class Reach
  def method_missing(method, *args)
    if reachable.respond_to?(method)
      reachable.send(method, *args)
    else
      super
    end
  end
end
  • Define each method that we want to delegate eg: from class reach to reachable
1
2
3
4
5
6
7
class Reach
  [:all, :my, :methods, :here].each do |m|
    define_method(m) do |*args|
      reachable.send(m, *args)
    end
  end
end
  • Using ActiveSupport delegate module extension in rails
1
2
3
4
5
6
7
class Door
  belongs_to :building
end

class Building
  has_many :windows
end

if we want to class door.name to return the name of the building associated to the given door, instead of creating a method that returns the name of the building, we can simply use the delegate method as:

1
2
3
4
class Door
  belongs_to :building
  delegate :name, to: :building
end