【Rails】delegateの使い方 オプションについても解説【Ruby】

サムネイル Ruby

結論

delegateはメソッドを委譲することができる

delegateを使うことで記述が短く済み、意味も明快となる

Userモデルにログイン情報があり、それに関連する名前などの情報はProfileモデルにあるとする。

class User < ApplicationRecord
  has_one :profile
end

class Profile < ApplicationRecord
  belongs_to :profile
end

user.profile.name
# => "山田太郎"

delegateを用いて記述すると、以下のようになる。

class User < ApplicationRecord
  has_one :profile
  delegate :name, to: :profile
end

class Profile < ApplicationRecord
  belongs_to :profile
end

user.name
# => "山田太郎"

基本機能

結論でも述べたように、メソッドを他のモデルから委譲することができます。

もしdelegateを使わずに他モデルのメソッドの使用するとなると、以下のようにそれぞれメソッドを定義しなければなりません。

class User < ApplicationRecord
  has_one :profile

  def name
    profile.name
  end

  def gender
    profile.gender
  end
end

class Profile < ApplicationRecord
  belongs_to :profile
end

user.name
# => "山田太郎"
user.gender
# => "male"

このまま必要になったメソッドを追加していけば、徐々に見通しの悪いmodelとなっていきます。

それを防ぐ技術がdelegateというわけです。

# Profileモデルは省略
class User < ApplicationRecord
  has_one :profile
  # Profileモデルからname, genderを委譲している。
  delegate :name, :gender, to: :profile
end

user.name
# => "山田太郎"
user.gender
# => "male"

Userモデルがとてもスッキリとしました。

オプション

prefix

prefixオプションは名前の通り、委譲するメソッドにprefixをつけることができます。

メソッド名は、委譲元のオブジェクト_メソッド名となります。

class User < ApplicationRecord
  has_one :profile
  delegate :name, :gender, to: :profile, prefix: true
end

# profileオブジェクトからnameを委譲しているため、profile_nameとなる。
user.profile_name
# => "山田太郎"
user.profile_gender
# => "male"

文字列 or シンボルでprefixを指定することでカスタマイズすることもできます。

class User < ApplicationRecord
  has_one :profile
  delegate :name, :gender, to: :profile, prefix: :test # or 'test'
end

# prefixをtestと指定しているため、test_nameとなる。
user.test_name
# => "山田太郎"
user.test_gender
# => "male"

allow_nil

委譲時にNoMethodErrorが発生して対象がnilの場合、NoMethodErrorが伝搬します。

allow_nilオプションを使うと、例外の代わりにnilを返すようにできます。

下記は、Profileモデルのnameがnilの場合の動作です。

# modelの設定(allow_nilなし) 
# delegate :name, to: :profile

user.name
# undefined method `name' for nil:NilClass (NoMethodError)


# modelの設定 (allow_nilあり)
# delegate :name, to: :profile, allow_nil: true

user.name
# => nil

private

privateオプションはメソッドのスコープを変更します。

委譲されたメソッドはデフォルトでpublicになりますが、private: trueを渡すことで変更できます。

 delegate :name, to: :profile, private: true

注意点

委譲されるのはpublicなメソッドのみ

モデル内にprivateメソッドを定義していて、それを委譲しようとしてもできません。

委譲しようとするメソッドがpublicであるか確認するようにしてください。

引用・参考資料

Active Support コア拡張機能 - Railsガイド
Active Supportで定義されているRubyのコア拡張機能に関するドキュメントです。
タイトルとURLをコピーしました