概要
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: "重複したの場合のメッセージ" }