Overview of method delegation in Rails

Posted . Visible to the public. Repeats.

Method delegation in Rails can help you to keep your code organized and avoid deep call chains (law of demeter) by forwarding calls from one object to another. Rails provides several ways to accomplish this. Below is a concise overview of the most common approaches:

Single-Method delegation with delegate

Use the built-in delegate method from ActiveSupport to forward specific methods:

class User < ApplicationRecord
  has_one :profile

  delegate :full_name, :age, to: :profile, prefix: true
end
  • delegate: full_name, :age, to: :profile forwards full_name and age to the profile association
  • prefix: true changes the delegated methods to profile_full_name and profile_age in the User class

This is ideal for forwarding a small number of methods without cluttering your model

Delegating all method calls via method_missing and respond_to_missing?

But what do we do if we want to forward all method calls to a different object? Do we have to keep a long list of all the methods and update it whenever changes are made?
Fortunately not, because there is a common pattern for this in Ruby. By overwriting method_missing and respond_to_missing? in our class, we can forward all method calls that are not explicitly defined in our own class to the wrapped object.

class UserDecorator
  def initialize(user)
    @user = user
  end

  private
  
  def respond_to_missing?(method_name, include_private = false)
    @user.respond_to?(method_name, include_private)
  end
  
  def method_missing(method_name, *args, &block)
    @user.public_send(method_name, *args, &block)
  end
end

Rails shortcut: delegate_missing_to

Because this is such a common pattern (e.g. for building something like decorators), Rails provides a shortcut: delegate_missing_to Show archive.org snapshot

class UserDecorator
  attr_reader :user
  delegate_missing_to :user

  def initialize(user)
    @user = user
  end
end

Rails automatically implements the necessary method_missing and respond_to_missing? for you, reducing boilerplate code.

Further reading

Dennis Schreiner
Last edit
Dennis Schreiner
License
Source code in this card is licensed under the MIT License.
Posted by Dennis Schreiner to makandra dev (2025-03-19 15:23)