LoginSignup
62
24

More than 5 years have passed since last update.

なぜか boolean の validates ~ presence がいつもエラーになる

Last updated at Posted at 2014-11-22

Active Record の Validation

Ruby on Rails の Active Record にある validates って便利ですよね。

class Person < ActiveRecord::Base
  validates :name, presence: true
end

というモデルがあったときに、name に値が入っているかをチェックしてくれて、ない場合にはエラーとかまっで設定してくれる。
便利 :thumbsup:

値があるのにバリデーションが false ???

ただ、boolean のフィールドでこれを使った際にちょっとつまづきました。

class Person < ActiveRecord::Base
  validates :name, presence: true
  validates :has_glasses, presence: true
end

というモデルがあるとして、

irb> person = Person.new(name: "Daisuke", has_glasses: false)
 => #<Person id: nil, name: "Daisuke", has_glasses: false>
irb> person.has_glasses
 => false
irb> person.valid?
=> false

false の値が has_glasses に設定されているはずなのにバリデーションが通りません。

???

で、少し調べてみると、これ、実は presence の動作が(僕個人の意見として)直感的でないのが原因でした。

presence の動作を定義している ActiveModel::Validations::PresenceValidator を見ると

class PresenceValidator < EachValidator
  def validate_each(record, attr_name, value)
    record.errors.add(attr_name, :blank, options) if value.blank?
  end
end

となっています。ここで注目すべきは if value.blank? です。ここで、value には false が入っているわけですが、そうなると…

irb> value = false
=> false
irb> value.blank?
 => true

となり、エラーとして認識されてしまいます!

さらに掘り下げると、どうやら、この blank? メソッド、Rails のライブラリの1つである ActiveSupportObject クラスに追加されているみたいです。

Ruby on Rails API より

def blank?
  respond_to?(:empty?) ? !!empty? : !self
end

booleanempty? メソッドがないので、!self の結果、つまり true が返されます。

正しい Boolean フィールドのチェック方法

Booelan のバリデーションを行う場合には ActiveModel::Validations::InclusionValidator (validates に書くときは inclusion) を使って

validates :has_glasses, inclusion: [true, false]

とするのがいいらしいです。

参考リンク

A Developer with a Pencil

62
24
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
62
24