前提条件
Userテーブルにnullを許容しないBoolean型のhoge_flagというカラムがあるとする。
create_table :users do |t|
t.boolean :hoge_flag, default: true, null: false
end
migration後にuser.rbにvalidatesを追加
validates :hoge_flag, presence: true
データ保存時にエラーが出る・・・
上記を踏まえて、hoge_flagをfalseにしてみた!
user = User.first
user.hoge_flag = false
user.save!
結果
Translation missing: ja.activerecord.errors.messages.record_invalid (ActiveRecord::RecordInvalid)
あらら・・・
もう少し確認してみると
user.valid?
=> false
もちろん、バリデーションに引っかかってる
エラー内容は
user.errors.messages
=> {:hoge_flag=>["を入力してください"]}
ん?????
値はちゃんとfalseを入れてるけど??
user.hoge_flag
=> false
入ってるよね
調べてみた
Railsガイドで改めてpresenceをみてみる。
このヘルパーは、指定された属性が空(empty)でないことを確認します。値がnilや空文字でない、つまり空でもなければホワイトスペースでもないことを確認するために、内部でblank?メソッドを使っています。
ほうほう。ここで重要なのは、
内部でblank?メソッドを使っています。
だな
ちなみにblank?
の挙動はドキュメントを見てみると
An object is blank if it's false, empty, or a whitespace string. For example, nil, '', ' ', [], {}, and false are all blank.
!address || address.empty?
とあるので、
false.blank?
=> true
となっていて、内部的にtrueが返ってバリデーションに引っかかってたというオチでした・・・
presence: true
この記述はずっと使ってきていたはずなのに、深読みせず空かどうかみるやつねみたいな感覚で使ってた怠惰な自分を反省します
解決法
じゃあ今回のパターンの場合にどう書けばいいかというと、
validates :boolean_field_name, inclusion: [true, false]
もしくは
validates :boolean_field_name, exclusion: [nil]
と書くと、falseでもバリデーションに引っかからずに値が保存出来ます!
まとめ
Railsは魔法が多い。
と常々思っていますが、いつも何気なく使っているメソッド等の挙動や内部処理をドキュメント等で確認することの大事さを今回改めて感じました。