アプリケーションには色々なレベルでバリデーションをかけることができますが、うっかりしていると微妙な差異で引っかかることがあります。
「値がある」という制約
「値がある」ことをRails環境で宣言するバリデーションとして、主なものが3つ考えられます。
- データベースで
NOT NULL制約を入れる - Railsのモデルで
validates :column, presence: trueを宣言する - フォームを
<input required>にする
ただ、これらはすべて意味合いだけでなく、何で制約されるかも違ってきます。
DBでのNOT NULL制約
データベースにNULL値を入れられないようにする、という制約です。
- メリット…データベースにかけてしまえば、(この制約自体をいじるような)よほど特殊な操作をしない限り、
NULL値が入る心配はない - 注意点…
NULL以外の空文字列1や、スペースだけの文字列は投入可能です。
Railsでのpresence制約
Railsレベルでpresence: trueを使うと、present?な値(数値は何でもtrue、文字列は空白文字以外が1文字でもあればtrue)しか通さなくなります。
- メリット…フォーム生成のときに読み取って
requiredを入れてくれる(こともある) - 注意点…直接DBに投げるような場合は無力
フォームへのrequired
フォームの<input>などにrequired属性をつけると、空文字列のままではフォームが送信できなくなります。
- メリット…送信前に指摘できる(状況に合わせてCSSを変更することもできる)ので、ユーザビリティは高い
- 注意点…空白文字だけの文字列は通る、ブラウザ内で実行するものなのでセキュリティ的にはほぼ無力
値ごとの挙動の違い
ということで、値ごとにそれぞれのレベルでどうなるか、という形でまとめ直します。
-
NULL…requiredでは拒否(数値系の場合)あるいは入力不能(文字列の場合)2、presenceやNOT NULLでも拒否 - 空文字列…
requiredやpresenceでは拒否、NOT NULLは通る - 空白文字だけの文字列…
requiredでは通る、presenceでは拒否、NOT NULLは通る
ということで、以下のようなことが考えられます。
- DBの
NOT NULLだけで運用していた場合、空文字列がDBに登録される3 -
requiredとpresenceを組み合わせた場合、空白だけの文字列がRailsレベルのバリデーションに当たるので、そういうのが入力されたときのユーザー体験を損ねる4
こういう「微妙な値域の違い」は、いろんな場面で出うるものなので、要注意かもしれません。