62
15

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

はじめに

Ruby on Railsを使ったプロジェクトに配属され、Railsを学び始めた新卒エンジニアです。コードを読む中で、見慣れないDelegateメソッドを見つけたので調べてみました。
本記事の対象者はRubyやRailsの初心者、オプジェクト指向プログラミング初心者向けの記事となっています。修正点や改善点などがあればコメントまでお願いします。

Delegateとは

あるオブジェクト(一般的にはモデルオブジェクト)から別のオブジェクトへのメソッド呼び出しを委譲するために使用されます。定義に関してはこちら

delegateの定義
delegate :カラム名, to: :委譲先のオブジェクト名

また、委譲できるメソッドは複数追加することが可能です。

複数のメソッドの委譲
class Order < ApplicationRecord
  belongs_to :customer
  delegate :name, :address, :phone_number, to: :customer, prefix: true
end

上記では、OrderモデルはCustomerモデルのname、address、phone_numberメソッドを同時に委譲しています。

DelegateメソッドはRailsアプリケーションの中であれば、特別な設定やインクルードなしに自動的に利用できます。しかし、Ruby on Railsを使わない純粋なRubyのプログラムでは、ActiveSupportライブラリを明示的にrequireして、該当のクラスでextend ActiveSupport::Concernを行う必要があります。

Ruby(Railsを使わない場合)
require 'active_support/core_ext/module/delegation'

class MyClass
  extend ActiveSupport::Concern
  # delegateメソッドを利用可能
end

具体例

CustomerとOrderの間の一対多の関係を示す図で、一人のCustomerが複数のOrderを持つ例を考えてみます。

具体例
  +-------------+     +-----------------+
  |  Customer   |     |   Order         |
  +-------------+     +-----------------+
  | - id        |<---  | - id            |
  | - name      |     | - product_name  |
  | - created_at|     | - product_price |
  | - updated_at|     | - quantity      |
  |             |     | - customer_id   |
  +------------+      | - created_at    |
                      | - updated_at    |
                      +-----------------+

Delegateを使わない場合

Ruby
class Customer < ApplicationRecord
  has_many :orders
end

class Order < ApplicationRecord
  belongs_to :customer

  def customer_name
    customer.name
  end
end

order = Order.first
puts order.customer_name

customer_nameメソッド内で明示的にcustomerオブジェクトのnameメソッドを呼び出しています。

Delegateを使って変更した場合

Ruby
class Customer < ApplicationRecord
  has_many :orders
end

class Order < ApplicationRecord
  belongs_to :customer

  delegate :name, to: :customer, prefix: true
end

order = Order.first
puts order.customer_name 

delegateを使うことでOrderオブジェクトから直接customer_nameメソッドを呼び出すことができます。このcustomer_nameメソッドは、Orderオブジェクトに関連づけられたCustomerオブジェクトのnameを返します。

prefixオプション

Delegateメソッドを使用してメソッドを委譲するとき、prefixオプションを指定することで、そのメソッド名に接頭辞が追加されます。この接頭辞は、委譲されるメソッドがどのオブジェクトから委譲されているのかを明示的に示すために役立ちます。

prelixをつけない場合
class Customer < ApplicationRecord
  has_many :orders
end

class Order < ApplicationRecord
  belongs_to :customer
  delegate :name, to: :customer
end

order = Order.first
puts order.name 

この方法では、CustomerのnameメソッドがOrderに直接委譲されているため、order.nameという表記でCustomerのname属性にアクセスできます。

上記だと、order.nameがOrder自体のname属性を指しているのか、それとも委譲されたCustomerのname属性を指しているのかが一見してわからないため誤解を招く可能性があります。そのため、Delegateメソッドのprefixオプションを使用して、委譲されたメソッド名に接頭辞を追加します。これにより、委譲元のオブジェクトが明確になり、コードの可読性が向上します。

まとめ

今回はメソッドの委譲をする際に用いるdelegateについて調べました。delegateを使用することでコードの可読性や保守性も向上するため、積極的に使っていきたいです。

参考

62
15
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
62
15

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?