Skip to main content Link Search Menu Expand Document (external link)

Delegate

This article will walk you through the process of using delegate method in rails. Along the way, we will also discuss the design principle behind this method.

Table of Contents

  1. What is delegate?
  2. Why do we need to use delegate?
  3. How to use delegate?

What is delegate?

delegate is a method in rails that provides a delegate class method to easily expose contained objects’ public methods as your own. In other words, through delegation you can use other model’s public methods directly.

Why do we need to use delegate?

There is a design principle in programming called “the law of demeter”, also called “the principle of least knowledge”. This principle implies that an entity should only talk to its close friends. To put it another way, an object should not call methods through another object. This principle reduces dependencies and helps build components that are loosely coupled for code reuse, easier maintenance, and testability.

For example, the code below violates the law of demeter:

  post = Post.first
  
  post.user.email      #=> email@domain.com

You should treat email as an own method of post instead.

  post = Post.first
  
  post.user_email      #=> email@domain.com
  #or
  post.email           #=> email@domain.com

For the codes above to work, we need to define a method called user_email or email in the post model. However, if we do this, the model will soon become crowded with this type of method. Luckily, there is a built-in rails method called delegate that can handle this type of situation.

How to use delegate?

To adhere to the law of demeter we should avoid using post.user.email. We need to use delegate to fix it.

To use delegate, you just need to add the delegate method on your model. In our case the post model.

#app/models/post.rb

class Post < ApplicationRecord
  #...
+ delegate :email, to: :user
  
  mount_uploader :image, ImageUploader
  #...
end

You can now use the email method directly.

<!--app/views/posts/index.html.erb-->

<!--...-->
<table>
<!--...-->
    <% @posts.each do |post| %>
        <!--...-->
          <td data-controller="clipboard">
-           <span data-clipboard-target="email"><%= post.user.email %></span>
+           <span data-clipboard-target="email"><%= post.email %></span>
            <button data-action="click->clipboard#copy">copy</button>
          </td>
        <!--...-->
    <% end %>
</table>
<!--...-->

There are also some options you can use in delegation

:toSpecifies the target object
:prefixPrefixes the new method with the target name or a custom prefix, this is optional
:allow_nilif set to true, prevents a NoMethodError to be raised. By default, this is false

You can use the prefix option to make the method more readable.

#app/models/post.rb

class Post < ApplicationRecord
  #... 
- delegate :email, to: :user
+ delegate :email, to: :user, prefix: :user
  
  mount_uploader :image, ImageUploader
  #...
end
<!--app/views/posts/index.html.erb-->

<!--...-->
<table>
  <!--...-->
    <% @posts.each do |post| %>
        <!--...-->
          <td data-controller="clipboard">
-           <span data-clipboard-target="email"><%= post.email %></span>
+           <span data-clipboard-target="email"><%= post.user_email %></span>
            <button data-action="click->clipboard#copy">copy</button>
          </td>
        <!--...-->
    <% end %>
</table>
<!--...-->

The prefix gave us more context on how email method is related to post.


Back to top

Copyright © 2020-2022 Secure Smarter Service, Inc. This site is powered by KodaCamp.