モデル検証の概要
データの内容の範囲をデータベースで定義することで、保存に制約をかけることができます。
それ以外にも、制約をモデル(Rubyコード)でチェックできたり、違反した場合のエラーメッセージを返すこともできます。データの内容のチェックは検証(Validation)と言い、RailsのモデルもRubyコードによって検証をする仕組みがあります。モデルの検証により、自由度の高いチェックとともに、エラーを伝えやすくできます。
モデル検証の仕組み
Railsにおけるモデルの検証は「オブジェクトをDBに保存・更新する前に検証を行い、エラーがあれば登録・更新をしないで差し戻す」という仕組みです。この仕組みに対応するメソッドがsaveです。
検証の書き方
検証コードは自分で記述する方法と、Railsが備えるヘルパーを利用する2通りがあります。後者でよく使われるのが以下の検証機能です。
検証内容 | ヘルパーの使い方の例 |
---|---|
必須のデータが入っているか? | validates :foo, presence: true |
数値以外が入っていないか?小数点の有無・正負が期待通りか? | validates :foo, numericality: true |
数値の範囲が期待通りか? | validates :foo, inclusion: { in: 0..9} |
文字列の長さが想定どおりか? | validates :foo, length: { maximum: 30} |
文字列のフォーマットや構成文字種が想定通りか? | validates :foo, format: { with: ・・・} validates :foo, inclusion: {in: ・・・} |
データが一意になっているか? | validates :foo, uniqueness: true |
パスワードやメールアドレスが、その確認用の入力と一致しているか? | validates :foo, confirmation |
モデルへの検証の追加(必須かどうかの検証)
作成したアプリのPostモデルのcontent属性の値が入っていなければ検証エラーになるように、検証を追加します。
class Post < ApplicationRecord
validates :content, presence: true
end
コントローラーの変更
次に、Postモデルが検証に引っかかった際にユーザーにわかりやすく表示し際入力を促す必要があります。まずは、コントローラーに変更を加えます。以前のcreateアクションを…
def create
post = Post.new(post_params)
post.save!
redirect_to posts_url, notice: "「#{post.content}」を投稿しました。"
end
次のように変更します。
def create
@post = Post.new(post_params)
if @post.save
redirect_to @post, notice: "「#{@post.content}」を投稿しました。"
else
render :new
end
end
投稿に用いるメソッドをsave!からsaveに変更しました。検証によりユーザーの入力次第で、投稿に失敗するするようになりました。そこで、失敗時に処理を中断してしまうsave!ではなく、例外を発生させるsaveにより戻り値を取得し、制御を変えるようにしています。
検証エラー次の処理を追加しました。検証結果がfalseだった場合、render :newによって投稿フォーム画面を再表示させ、際入力を促します。
Postオブジェクトをインスタンス変数に代入させました。エラー時に投稿画面を再表示させる際に、ビューに検証を行った現物のPostオブジェクトを渡す必要があるからです。@postをビューに伝えることで、次の2点の効果が生まれます。
- 前回入力したままのデータがフォームに入った状態を引き継いで表示できる。
- Postオブジェクトが抱える検証エラーの内容をユーザーに表示できる。
ビューの変更
続いてビューの変更を行ます。
検証エラーメッセージを表示するため、form_withの上にメッセージ領域を作成します。
- if post.errors.present?
ul#error_explanation
- post.errors.full_messages.each do |message|
li= message
= form_with model: post, local: true do |f|
…
errors.present?で検証エラーの有無を調べ、エラーがある時にエラーメッセージを表示するようにしています。
モデル検証の追加(文字列の長さの検証)
DBの定義でcontentカラムの文字列を50文字以下に制限したので、ユーザーにわかるよう検証エラーを実装します。
validatesは、同じ属性に対して複数の検証を1行に書くことができます。
class Post < ApplicationRecord
validates :content, presence: true, length: { maximum: 50 }
end