[quads id=1]
今回はメソッドを委譲することができるdelegateメソッドについて簡単に解説したいと思います。「メソッドの委譲」と聞くと難しいイメージを抱きますが、使い方は比較的簡単ですので順番に見ていきましょう。
delegateメソッドとは
delegateとは、メソッドを委譲することができるメソッドになります。
例を見ていきます。
以下のようにUserモデルとPostモデルがあり、それらが1対多の関係で紐づいていると仮定します。またUserモデルはnicknameカラムを持っているとします。
# Userモデルはnicknameカラムを持つ
class User < ApplicationRecord
has_many :posts
endclass Post < ApplicationRecord
belongs_to :user
end
ここで、ある投稿(post)に紐づいたユーザ(user)の名前(nickname)を取得したいとなった場合、以下のようなコードを書くことで実現できます。
# ある投稿に紐づいたユーザ名を取得する
post.user.nickname
Postモデルにnicknameというメソッドを定義することで、よりシンプルにユーザー名を取得することができるようにもなります。
class Post < ApplicationRecord
belongs_to :user
def nickname
user.nickname
end
end# ある投稿に紐づいたユーザ名を取得する
post.nickname
しかし上記のコードは、delegateメソッドを用いることでさらにシンプルに記述することができるようになります。
先ほどのnicknameというメソッドをdelegateを用いて移譲します。delegateの後ろには委譲したいメソッド名(カラム名)、to:の後ろには関連先(アソシエーション先)を記載します。
class Post < ApplicationRecord
belongs_to :user
delegate :nickname, to: :user
end# ある投稿に紐づいたユーザ名を取得する
post.nickname
複数のメソッドを委譲したい場合は、以下のように記述することも可能です。
class Post < ApplicationRecord
belongs_to :user
delegate :nickname, :age, :gender, :status, to: :user
end
このようにdelegateメソッドを使用することで、メソッドチェーンを多用することなく実装を行うことができるようになります。
定義方法
delegateメソッドは以下のように定義することができます。
delegate :カラム名, to: :アソシエーション名delegateメソッドのオプション
allow_nil
アソシエーション先がない状態でdelegateメソッドを使用すると、NoMethodErrorが発生してしまいます。allow_nilオプションを付与することで、例外の代わりにnilを返すことができるようになります。
例を見てみましょう。
以下のようにdelegateメソッドを定義していますが、アソシエーション先がnilだと仮定します。この場合、ある投稿に紐づいたユーザ名を取得するためpost.nicknameをするとNoMethodErrorが発生してしまいます。
class Post < ApplicationRecord
belongs_to :user
delegate :nickname, to: :user
endある投稿に紐づいたユーザ名を取得する
post.nickname
=> NoMethodErrorが発生する
しかし以下のようにallow_nilオプションを付与することで、NoMethodErrorを回避することができます。
class Post < ApplicationRecord
belongs_to :user
delegate :nickname, to: :user, allow_nil: true
endある投稿に紐づいたユーザ名を取得する
post.nickname
=> nil
ぼっち演算子を付与した場合と同様の挙動ですね。
class Post < ApplicationRecord
belongs_to :user
def nickname
user&.nickname
end
endある投稿に紐づいたユーザ名を取得する
post.nickname
=> NoMethodErrorが発生するprefix
prefixオプションをtrueにすることで、生成されたメソッド名に対してプレフィックスを追加することができます。既に同名のメソッド名を持っている場合に使えるオプションになります。
例を見てみましょう。
以下のようにprefix: trueを付与した場合、nicknameではなく、user_nicknameというメソッドが生成されます。そのため、ある投稿に紐づいたユーザ名を取得する記述はpost.user_nicknameとなります。
class Post < ApplicationRecord
belongs_to :user
delegate :nickname, to: :user, prefix: true
end# ある投稿に紐づいたユーザ名を取得する
post.user_nickname
またprefixオプションは以下のようにカスタマイズすることも可能です。
class Post < ApplicationRecord
belongs_to :user
delegate :nickname, to: :user, prefix: :avator
end# ある投稿に紐づいたユーザ名を取得する
post.avator_nicknameprivate
delegateメソッドで定義されたメソッドは、デフォルトでpublicなメソッドになるためどこからでもアクセスが可能になります。
アクセスを制限した場合は、privateオプションを付与することでメソッドのスコープを変更することができます。
class Post < ApplicationRecord
belongs_to :user
delegate :nickname, to: :user, private: true
end
以下のようにprivateメソッドを付与した場合と同じになりますね。
class Post < ApplicationRecord
belongs_to :user
private
def nickname
user.nickname
end
endインスタンス変数や定数へもアクセスも可能
delegateメソッドはインスタンス変数や定数へのアクセスも可能です。
# インスタンス変数へのアクセス
delegate :nickname, to: :@user
# 定数へのアクセス
delegate :nickname, to: :USER_CONSTANT全て委譲したいならdelegate_missing_toメソッド
delegate_missing_toメソッドを使用することで、全てのメソッドを委譲することができます。以下のような、委譲するメソッドが大量にある場合に便利なメソッドになります。
delegate :nickname, :age, :gender, :status, :postal_code, :address, relationship, to: :userclass Post < ApplicationRecord
belongs_to :user
delegate_missing_to :user
endまとめ
- delegateとは、メソッドを委譲することができるメソッド
- delegateは複数メソッドを委譲することも可能
- allow_nilオプションを付与することで、例外の代わりにnilを返すことができる
- prefixオプションをtrueにすることで、生成されたメソッド名にプレフィックスを追加することができる
- prefixはカスタマイズすることも可能
- privateオプションを付与することでメソッドのスコープを変更することができる
- delegateメソッドはインスタンス変数や定数へのアクセスも可能
- delegate_missing_toメソッドを使用することで、全てのメソッドを委譲することができる
参考
今回はメソッドを委譲することができるdelegateメソッドについて解説しました。delegateメソッドを使用することで、クラスメソッドを省略したり、アソシエーションの記述を減らしたりとコードをスッキリさせることができます。ぜひこの機会に使ってみてください。







