Posted at

[Rails][Model] validate :if options

More than 5 years have passed since last update.

http://guides.rubyonrails.org/active_record_validations.html#conditional-validation

5 Conditional Validation

Sometimes it will make sense to validate an object only when a given predicate is satisfied. You can do that by using the :if and :unless options, which can take a symbol, a string, a Proc or an Array. You may use the :if option when you want to specify when the validation should happen. If you want to specify when the validation should not happen, then you may use the :unless option.

validateを条件付きで行うには:if:unlessオプションを使う。

引数は、シンボル、文字列、Proc、配列のいずれかである。

5.1 Using a Symbol with :if and :unless

You can associate the :if and :unless options with a symbol corresponding to the name of a method that will get called right before validation happens. This is the most commonly used option.

class Order < ActiveRecord::Base

validates :card_number, presence: true, if: :paid_with_card?

def paid_with_card?
payment_type == "card"
end
end

シンボルを渡すときは、そのシンボル名のメソッドが呼ばれて、判定する。

5.2 Using a String with :if and :unless

You can also use a string that will be evaluated using eval and needs to contain valid Ruby code. You should use this option only when the string represents a really short condition.

class Person < ActiveRecord::Base

validates :surname, presence: true, if: "name.nil?"
end

文字列を渡すときは、その文字列がevalで評価され、その結果で判定する。

5.3 Using a Proc with :if and :unless

Finally, it's possible to associate :if and :unless with a Proc object which will be called. Using a Proc object gives you the ability to write an inline condition instead of a separate method. This option is best suited for one-liners.

class Account < ActiveRecord::Base

validates :password, confirmation: true,
unless: Proc.new { |a| a.password.blank? }
end

Procを渡すと、Procが評価され、その結果で判定する。

5.4 Grouping Conditional validations

Sometimes it is useful to have multiple validations use one condition, it can be easily achieved using with_options.

class User < ActiveRecord::Base

with_options if: :is_admin? do |admin|
admin.validates :password, length: { minimum: 10 }
admin.validates :email, presence: true
end
end

All validations inside of with_options block will have automatically passed the condition if: :is_admin?

ひとつの条件判定で複数のvalidateをするときはwith_optionsでまとめることができる。

5.5 Combining Validation Conditions

On the other hand, when multiple conditions define whether or not a validation should happen, an Array can be used. Moreover, you can apply both :if and :unless to the same validation.

class Computer < ActiveRecord::Base

validates :mouse, presence: true,
if: ["market.retail?", :desktop?]
unless: Proc.new { |c| c.trackpad.present? }
end

The validation only runs when all the :if conditions and none of the :unless conditions are evaluated to true.

逆に、複数の条件で判定して、一つのvalidationを実行するときは、if:に配列を渡すことができる。