環境
Railsのバージョンは4.1です。
$ rails -v Rails 4.1.1
そもそもwith_optionsって?
オプションの記述が冗長にならないようにまとめてくれる便利メソッドです。
class User < ActiveRecord::Base validate :name, presence: true, if: :hoge validate :address, presence: true, if: :hoge validate :email, presence: true, if: :hoge end
例えば上記はこう書けます。
class User < ActiveRecord::Base with_options if: :hoge do |u| u.validate :name, presence: true u.validate :address, presence: true u.validate :email, presence: true end end
validateで使うことが多いですが、他にもいろいろ使えます。
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 if:
の中でif:
を使うと上書きされてしまう。
例えば下記の場合、
class User < ActiveRecord::Base with_options if: A do |u| u.validate :name, presence: true u.validate :address, presence: true, if: B end end
adressはif Aand B
にはならず、if: B
になる
class User < ActiveRecord::Base u.validate :name, presence: true, if: A u.validate :address, presence: true, if: B #=> 条件Aは無視 end
対処法
with_optionsの中で同じオプションを使わない
さきほどの場合は、unless:
を使って対応します。
class User < ActiveRecord::Base with_options if: A do |u| u.validate :name, presence: true u.validate :address, presence: true, unless: !B #=> if: Bと等価 end end
with_optionsを分ける
ネストが増えそうな場合はそもそも分けてやったほうがいいです。
class User < ActiveRecord::Base with_options if: A do |u| u.validate :name, presence: true end with_options if: [A, B] do |u| u.validate :address, presence: true end end
以上です。 意外とハマりがちなので注意しましょう〜。