10
7

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Ruby on RailsAdvent Calendar 2018

Day 24

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

Last updated at Posted at 2018-12-23

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

「値がある」という制約

「値がある」ことを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. もっとも、「空白だけの文字列」が正当な入力となりうる場面も、そう多くない気はします。

10
7
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
10
7

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?