Help us understand the problem. What is going on with this article?

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

More than 5 years have passed since last update.

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

diskshima
株式会社プログリットという英語コーチングの会社でソフトウェア・エンジニアをやっています。 好きなエディタは Vim です。
integrity-healthcare
テクノロジーを活用した医師の診療支援ソリューションの開発・提供
https://www.integrity-healthcare.co.jp/
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away