delegateとは
Railsにおけるdelegate
は移譲する
の意味で使われていると思われます。
delegateメソッドを使うことによって、異なるクラスに定義されているメソッドをそのオブジェクトのメソッドとして呼び出せます。
これによって、リレーションを持つクラスのインスタンスメソッドを委譲することができます。
user has_many posts && post belongs to use
の場合を考えます
- User(id: integer, name: string, age: integer)
- Post(id: integer, title: string, content: string)
delegateを使わずにuserのnameを参照する場合
post = Post.first
post.user.name
delegateを使って参照する場合
class Post < ApplicationRecord
belongs_to :user
delegate :name, to: :user
end
post = Post.first
post.name
このように、リレーション関係にあるクラスのメソッドをそのオブジェクトのメソッドであるかのように使うことができます。
delegateメソッドを呼び出すことによって何が起こっているのかというと、呼び出したクラスにインスタンスメソッドが定義されます。
- delegateメソッドを使っていない場合
pry(main)> Post.instance_method(:name)
# => NameError: undefined method `name' for class `Post (call 'Post.connection' to establish a connection)'
- delegateメソッドを使った場合
pry(main)> Post.instance_method(:name)
# => #<UnboundMethod: Post (call 'Post.connection' to establish a connection)#name(...) /app/app/models/post.rb:14>
delegateメソッドを使う際には、1対1の関係であることと、指定するメソッドがpublicメソッドである必要があります。
上記の例で言えば、user has_many posts
であるため、PostクラスのインスタンスメソッドをUserクラスにおけるdelegateメソッドの引数に指定することはできません。
オプション
delegateメソッドのオプションには:to
, :prefix
, :allow_nil
, :private
があります
-
to
:to
では、ターゲットになるオブジェクトを指定します。基本的にはbelongs_to
,has_one
の対象になるオブジェクトと同じと考えていいかと思います。 -
prefix
prefixをつけることができます。下記のようにprefixを指定すると、post.hello_name
のように参照することができるようになります。
delegate :name, to: :user, prefix: :hello
-
allow_nil
allow_nil: true
を指定すると、Module::DelegationError
が生じなくなります。 -
private
private: true
を指定するとprivateメソッドとして、自クラスに定義されます。
参考にしたサイト