アプリケーションには色々なレベルでバリデーションをかけることができますが、うっかりしていると微妙な差異で引っかかることがあります。
「値がある」という制約
「値がある」ことを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
こういう「微妙な値域の違い」は、いろんな場面で出うるものなので、要注意かもしれません。