LoginSignup
13
13

More than 5 years have passed since last update.

Railsのwith_options

Posted at

with_optionsという便利メソッドの存在を知る。

Object.with_options`を使うとオプションパラメタをまとめる事ができます。

例えばこういうのを、

class Account < ActiveRecord::Base
  has_many :customers, dependent: :destroy
  has_many :products,  dependent: :destroy
  has_many :invoices,  dependent: :destroy
  has_many :expenses,  dependent: :destroy
end

こう書けます。

class Account < ActiveRecord::Base
  with_options dependent: :destroy do |assoc|
    assoc.has_many :customers
    assoc.has_many :products
    assoc.has_many :invoices
    assoc.has_many :expenses
  end
end

with_optionsの引数に渡したHashのオプションの値がブロック内に適用されます。上の例ではhash_manydependentオプションを共通化しましたが、他のパターンでも適用できます。例えば、モデルの例では他にもvalidatesメソッドのオプションを共通化など使えます。

動作としては、with_optionsに引数として与えたHashを、ブロック内の各メソッドの引数のオプションHashにdeepマージする挙動なのでモデル以外でも使えます。

定義はactivesupport/lib/active_support/core_ext/object/with_options.rbにある。

ただハマりポイントもあり

  • deepマージする挙動なので、with_optionsとブロック内メソッドで同じkeyでオプションを定義すると片方が適用されない
  • Rails 4.1 以前ではレシーバオブジェクト経由で本来のメソッドを呼ぶことが必須
    • Rails 4.1ではwith_optionsからブロックへ渡されるレシーバオブジェクト(上の例のassoc)経由で本来のメソッドを呼ぶ必要あり(上の例のassoc.has_many。レシーバ省略してメソッドを呼ぶと効かない。
    • Rails 4.2 からはレシーバ省略可能

実際、Rails HEADのドキュメントにはレシーバ無しで呼べると書かれててて、4.1でそう書いたら動かなくてハマりました。

参考文献

13
13
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
13
13