はじめに
Ruby on Railsを使ったプロジェクトに配属され、Railsを学び始めた新卒エンジニアです。コードを読む中で、見慣れないDelegateメソッドを見つけたので調べてみました。
本記事の対象者はRubyやRailsの初心者、オプジェクト指向プログラミング初心者向けの記事となっています。修正点や改善点などがあればコメントまでお願いします。
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を行う必要があります。
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を使わない場合
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を使って変更した場合
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オプションを指定することで、そのメソッド名に接頭辞が追加されます。この接頭辞は、委譲されるメソッドがどのオブジェクトから委譲されているのかを明示的に示すために役立ちます。
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を使用することでコードの可読性や保守性も向上するため、積極的に使っていきたいです。
参考