はじめに
Railsで定義したモデルクラスには、Active Modelが提供する検証クラスによって様々なバリデーションを宣言することができます。
ユーザーからの入力をシンプルなコードで検証できる大変便利な機能なのですが、使用する度に忘れてしまうので、基本的なものだけでも覚えるために記事に起こしておきます。
注意:以下、Rails 5系をベースにした内容になります
検証対象の作成
何はともあれ検証対象となるモデルが必要になるので、Rails new
からのscaffold
でUserモデルをサクッと作成します。
$ rails new validation_test
$ rails g scaffold User name:string age:integer group:string email:string
バリデーションの宣言
バリデーションは、モデルクラスにvalidates
メソッドを記述することで定義できます。
まずは、先ほど作成したUserモデルのnameカラムに存在性のバリデーションを定義してみます。
class User < ApplicationRecord
validates :name, presence: true
end
validatesメソッドは、第一引数に検証対象のフィールド名、第二引数に検証ルール名とそのパラメーターのハッシュをとります。(presenceルールにはパラメーターがないため、単にtrueとのみ記載する)
この状態でUserモデルの新規作成・更新などを行おうとした時、いずれかのフィールドが空だとエラーが発生します。
デフォルトでは、このようにエラーメッセージの表示ととフォームの強調表示をしてくれます。
検証するフィールドは、以下のように一度に複数個指定することも可能です。
class User < ApplicationRecord
validates :name, :email, :age, :group, presence: true
end
また、後述するlength検証などと合わせて、一度に複数の検証を宣言する場合は以下のように記述します。
class User < ApplicationRecord
validates :name, presence: true, length: { is: 5 }, uniqueness: true
end
バリデーションが機能するタイミング
バリデーションはレコードの新規作成・更新の際に機能すると書きましたが、具体的には以下のメソッドを実行しようとした時点で検証が行われます。
- create, create!
- save, save!
- update, update!
これら以外の、例えばincrement!
やtoggle!
、update_attribute
などのメソッドを使用した際には、定義したバリデーションが機能せずにそのままDBに書き込まれてしまいます。
そのため、検証が不要なフィールドや事前に何らかの検証が行われているといった場合以外では、可能な限り上記のメソッドを使った方が安全です。
また、モデルオブジェクトに対してvalid?
メソッドを用いると、DBへの保存とは関係なくオブジェクトがvalidな状態かどうかを真偽値で返してくれます。
様々な検証機能
先に挙げたpresence
検証以外にも、Railsには多くの検証機能が存在します。
非存在性の検証
absence
検証を用いると、値が空であるかどうかの認証ができます。特定の条件下では入力されたくないフィールドがある場合に使えますね。
# groupフィールドへの入力を禁止する
validates :group, absence: true
文字列長の検証(length)
length検証を使用すると、入力された文字列の長さのチェックを行ってくれます。
指定できるパラメーターには、最小の長さを定めるminimum
、逆に最大の長さを定めるmaximum
などがあります。
# 最長文字数を10文字に設定する
validates :name, length: { maximum: 10 }
# 最小文字数を10文字に設定する
validates :name, length: { minimum: 3 }
# 最小・最大文字数を同時に検証する
validates :name, length: { maximum: 10, minimum: 3 }
# ぴったり5文字の文字列のみ許可する
validates :name, length: { is: 5 }
数値の検証(numericalcality)
numericalcality
検証を宣言すると、数値入力が期待されるフィールドに対して数値チェックや大小チェックなどが行えます。
# 入力値が数値かどうかを検証する
validates :age, numericality: true
# 入力値が整数かどうかを検証する
validates :age, numericality: { only_integer: true }
# 指定した値よりも大きいかどうか
validates :age, numericality: { greater_than: 5 }
# 指定した値以上かどうか
validates :age, numericality: { greater_than_or_equal_to: 5 }
# 指定した値よりも小さいかどうか
validates :age, numericality: { less_than: 100 }
# 指定した値以下かどうか
validates :age, numericality: { less_than_or_equal_to: 100 }
# 指定した値と同値かどうか
validates :age, numericality: { equal_to: 20 }
# 奇数かどうか
validates :age, numericality: { odd: true }
# 偶数かどうか
validates :age, numericality: { even: true }
範囲内 or 範囲外の検証(inclusion/exclusion)
inclusion
検証を使用すると、値が指定のリストの中に含まれるか、もしくは指定の範囲に含まれるかどうかを検証できます。
対してexclusion
検証を使用すると、値が指定のリストの中に含まれていないか、もしくは指定の範囲に含まれていないかどうかを検証できます。
ホワイトリスト、ブラックリストの定義に使えますね。
# 入力値がA, B, Cのいずれかの文字列であるかどうか
validates :group, inclusion: { in: %w[A B C] }
# 同じ内容を範囲オブジェクトで指定することもできる
validates :group, inclusion: { in: ('A'..'C') }
# exclusionはinclusionの逆
validates :group, exclusion: { in: %w[A B C] }
validates :group, exclusion: { in: ('A'..'C') }
正規表現による検証(format)
format
検証を用いると、入力された文字列が指定した正規表現にマッチするかどうかの検証を行えます。正規表現はwithパラメーターの値として指定します。
emailなど、一定のパターンに当てはまる値を期待する場合に指定することになるかと思います。
# 入力値がA, B, Cのいずれかの文字列であるかどうか(inclusionの例と同じ)
validates :group, format: { with: /\A[ABC]\Z/ }
# emailの形式かどうかチェックする
email_regex = /\A[a-zA-Z0-9.!#$%&'*+\/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*\Z/
validates :email, format: { with: email_regex }
ユニークネス検証(uniqueness)
uniqueness
検証を用いると、入力値がそのフィールドにおいて一意なものかどうかの検証を行ってくれます。重複を許さないデータ、例えばメールアドレスなどの検証に使えるかと思います。
オプションとして、パラメーターのcase_sensitive
を使用すると、大文字・小文字の区別を行うかどうかを設定できます。(デフォルトでは有効(true)。)
また、2つ以上のフィールドの組み合わせにおいて一意になるようにしたい!という場合は、パラメーターにscope
を使用することで実現できます。
# メールアドレスの一意性を検証する
validates :email, uniqueness: true
# 大文字・小文字の区別を行わない
validates :email, uniqueness: { case_sensitive: false }
# グループごとにメールアドレスの一意性を検証する
validates :email, uniqueness: { scope: :group }
参考
- HTML リビングスタンダード(emailの正規表現)
- Active Record バリデーション - Rails ガイド