LoginSignup
6

More than 3 years have passed since last update.

posted at

updated at

「値あり」バリデーションの微妙な違い

アプリケーションには色々なレベルでバリデーションをかけることができますが、うっかりしていると微妙な差異で引っかかることがあります。

「値がある」という制約

「値がある」ことを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を変更することもできる)ので、ユーザビリティは高い
  • 注意点…空白文字だけの文字列は通る、ブラウザ内で実行するものなのでセキュリティ的にはほぼ無力

値ごとの挙動の違い

ということで、値ごとにそれぞれのレベルでどうなるか、という形でまとめ直します。

  • NULLrequiredでは拒否(数値系の場合)あるいは入力不能(文字列の場合)2presenceNOT NULLでも拒否
  • 空文字列…requiredpresenceでは拒否、NOT NULLは通る
  • 空白文字だけの文字列…requiredでは通る、presenceでは拒否、NOT NULLは通る

ということで、以下のようなことが考えられます。

  • DBのNOT NULLだけで運用していた場合、空文字列がDBに登録される3
  • requiredpresenceを組み合わせた場合、空白だけの文字列がRailsレベルのバリデーションに当たるので、そういうのが入力されたときのユーザー体験を損ねる4

こういう「微妙な値域の違い」は、いろんな場面で出うるものなので、要注意かもしれません。


  1. Oracle Databaseは空文字列をNULLと同じ扱いをするため、事情が違ってきます。 

  2. 文字列の列でNULLを活用したい場合、Railsレベルのライフサイクルコールバックで変換を入れるなど特殊な手段が必要となります。 

  3. DBレベルのバリデーションだけだと、引っかかった場合にデータベースエラーとなってハンドリングが難しいので、あまり実用的ではないです。 

  4. もっとも、「空白だけの文字列」が正当な入力となりうる場面も、そう多くない気はします。 

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
What you can do with signing up
6