概要
Railsでモデルを介してフォーム入力を扱う場合、入力データが適正かどうか条件を設定して検証できる。
検証の条件はvalidatesをモデルクラス内で定義し、saveやvalid?などのメソッド実行に際して検証が行われる。これらのメソッドは検証結果の適正/不適正によってtrue/falseの戻り値を持つので、その結果に応じてflashによるエラー表示などの処理を行うことができる。
バリデーションの記述
モデルクラスの定義で以下を記述。
validates:(:対象カラム , 検証内容1, 検証内容2, ...) 
たとえばUserモデルのnameの存在と長さを検証する場合は以下のように書く。
app/models/user.rb
| 1 2 3 | class User < ApplicationRecord   validates :name, presence: true, length: { maximum: 10 } end | 
バリデーションの確認
通常、モデル内にvalidatesを書くと、モデルのsave実行前に検証が行われる。
モデルインスタンスのvalid?を実行すると、その時点でモデルの内容が妥当かどうかが検証され、検証結果が妥当であればtrue、妥当でなければfalseが返される。
また、妥当でない場合のエラーの内容は、モデルのerrors.messagesで確認できる。
app/controllers/users_controller.rb
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | class UsersController < ApplicationController   .....   def sign_up_process     user = User.new(user_params)     p user.name     p user.valid?     p user.errors.messages   end   private   def user_params     params.require(:user).permit(:name, :email, :password)   end end | 
たとえば検証結果が妥当な場合のRailsサーバーのログは、
| 1 2 3 | "0123456789" true {} | 
何も入力しなかった場合は、
| 1 2 3 | "" false {:name=>["can't be blank"]} | 
長さが制限を超えた場合は、
| 1 2 3 | "01234567890" false {:name=>["is too long (maximum is 10 characters)"]} | 
バリデーションの種類
presence~存在確認
<書式>
presence: true
入力内容がnil、空文字列、スペースでないことを検証する。全角スペースも検証の対象となる。内部でblank?メソッドを使っている。
<実行例>
モデル
| 1 |   validates :name, presence: true | 
errors.messages
| 1 | {:name=>["can't be blank"]} | 
逆にnil、空文字列、スペースのみであることを検証する場合はabscenceを使う。
length~長さの検証
<書式>
length: { 制限オプション: 制限値 }
長さを検証する。制限オプションと制限値のパターンは以下の通り。
- :minimum:長さの最小値- 例:{ minimum: 10 }
 
- 例:
- :maximum:長さの最大値
- 例:{ maximum: 20 }
 
- 例:
- :is:長さがこの値に一致しなければならない
- 例:{ is: 10 }
 
- 例:
- :in/:witnin:長さの範囲
- 例:{ in: 10..20 }
 
- 例:
<実行例>
モデル
| 1 2 | validates :name, length: { is: 6 } validates :password, length: { in: 6..20 } | 
errors.messages
| 1 2 | {:name=>["is too short (minimum is 6 characters)"]} {:name=>["is the wrong length (should be 6 characters)"]} | 
numericality~数値の検証
<書式>
numericality: true
numericality: { 制限オプション: 制限値 }
入力内容が数値形式であることを検証する。デフォルトでは整数・実数にマッチするが、制限オプションでいろいろなパターンを検証できる。
- :only_integer:整数
- :even/:odd:偶数/奇数
- :equal_to:与えた数に等しい
- :other_than:与えた数以外
- :greater_than:与えた数より大きい
- :greater_than_or_equal_to:与えた数より大きい
- :less_than:与えた数より大きい
- :less_than_or_equal_to:与えた数より大きい
<実行例>
| 1 2 3 | class User < ApplicationRecord   validates :number, numericality: { greater_than: 3.5 } end | 
errors.messages
| 1 | {:name=>["must be greater than 3.5"]} | 
format~パターンマッチング
<書式>
format: { with: 正規表現 }
入力のパターンが正規表現にマッチするかどうか検証する。正規表現を定数に設定しておく書き方が使われる。
<実行例>
モデル
| 1 2 3 4 | class User < ApplicationRecord   VALID_EMAIL_REGEX = /\A([\w+-]+.?[\w+-]+)+@([\w-]+.?[\w-]+)+.[\w-]+\z/i   validates :email, format: { with: VALID_EMAIL_REGEX } end | 
errors.messages
| 1 2 | "a..a@aa.aa" {:email=>["is invalid"]} | 
検証結果のメッセージ
メッセージの構造
検証結果のエラーが1つの場合の、バリデーションのメッセージを確認する。
| 1 2 3 | class User < ApplicationRecord   validates :name, length: { maximum: 20 } end | 
入力値とメッセージの内容は以下の通り。
| 1 2 3 4 | "012345678901234567890" false {:name=>["is too long (maximum is 20 characters)"]} "is too long (maximum is 20 characters)" | 
この出力は以下のコードで表示させている。出力結果から、errors.messagesの内容は以下のようであることがわかる。
- errors.messagesはハッシュ
- ハッシュの キーはモデル名
- ハッシュの値は配列で、配列の要素はメッセージ文
これを踏まえて、以下のコードの10行目のように取り出している。
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | class UsersController < ApplicationController   .....   def sign_up_process     user = User.new(user_params)     p user.name     p user.valid?     p user.errors.messages     p user.errors.messages[:name][0]   end   ..... end | 
複数の検証を設定した場合
1つの要素に複数の検証を設定し、それらがエラーになった場合を考える。
| 1 2 3 | class User < ApplicationRecord   validates :name, length: { maximum: 20 }, format: { with: /\A[a-z0-9]\z/i } end | 
errors.messagesがハッシュなので、eachでキーと値を取り出し、その値が配列なのでeachで各メッセージを取り出す。
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | class UsersController < ApplicationController   .....   def sign_up_process     user = User.new(user_params)     p user.name     p user.email     p user.password     p user.valid?     p user.errors.messages     user.errors.messages.each do |key, messages|       p key       messages.each do |message|         p message       end     end   end   ..... end | 
表示結果は以下の通り。
| 1 2 3 4 5 6 | "012345678901234567890" false {:name=>["is too long (maximum is 20 characters)", "is invalid"]} :name "is too long (maximum is 20 characters)" "is invalid" | 
message:~メッセージの定義
メッセージは英語の文字列だが、message:で検証項目ごとのメッセージを定義できる。たとえば上の例で長さとパターンのそれぞれにメッセージを追加した例。
| 1 2 3 4 | class User < ApplicationRecord   validates :name, length: { maximum: 20, message: "名前は20文字以内にしてください" }, \                    format: { with: /\A[a-z0-9]\z/i, message: "名前に使える文字は英数字のみです"} end | 
実行結果は以下の通り。
| 1 2 3 4 5 6 | "012345678901234567890" false {:name=>["名前は20文字以内にしてください", "名前に使える文字は英数字のみです"]} :name "名前は20文字以内にしてください" "名前に使える文字は英数字のみです" | 
presenceやuniquenessの場合は以下のように定義する。
presence: { message: "未入力の場合のメッセージ" }
uniqueness: { message: "重複したの場合のメッセージ" }