LoginSignup
3
1

More than 1 year has passed since last update.

boolean型にpresence: trueは使えない

Last updated at Posted at 2023-05-02

発端

validates :is_active, presence: true

boolean型のカラムに対して、presence: trueのバリデーションをかけていました。

is_activeをfalseにしてsaveすると...

example = ExampleModel.new(is_active: false)
example.save # => false

example.errors.full_messages
# => ["Is active can't be blank"]

Is active can't be blank エラーが起きてしまいました。

原因

presence: trueは空かどうかの判定にblank?メソッドを使っているからです。
presence.rbにはこう記述されています。

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

つまりvalue.blank?の結果がtrueならバリデーションエラーということですね。

今回はvalueにfalseが入っているので、false.blank?が実行されることになりますが,その結果が以下です。

value = false
value.blank?
# => true

疑問

falseっていう値入ってるのに空の判定なの?

今度はblank.rbを見に行きます。

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

オブジェクトがempty?メソッドを持っていればempty?を実行し、真偽値に変換しています。

しかし、falseのクラスであるFalseClassはempty?が使えません。↓

false.class #=> FalseClass
FalseClass.respond_to?(:empty?) # => false

そのためself(自分自身)であるfalseにnotをつけた!falseが実行され、false.blank?はtrueとなるのです。

false.blank?がtrueということは、空だったと判定され、can't be blank のバリデーションエラーが起きるようです。

解決方法

validates :is_active, inclusion: { in: [true, false] }

参考記事

3
1
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
3
1