バリデーションとは
dbへデータを保存する際に、そのデータが意図したものかどうか検証する仕組み。
例)何かを投稿するときに名前を入力必須にする、パスワードの文字数は4文字以上、等々。
目標
インスタのような画像投稿SNSで、画像を投稿する際、未入力項目があれば、エラーメッセージを表示できるようにする。
モデルとカラムは以下の前提。
- モデル:PostImage
- カラム:shop_name、image
設定手順
<おおまかな流れ>
- モデルで、バリデーションの条件を設定
- コントローラで、エラー時の処理を設定
- Viewで、エラーメッセージを表示
1. モデルでバリデーションの条件を設定
validates :カラム名, 条件
条件には色んなオプションがあります(後述)。
今回は未入力かどうかを検証するため、presence :true
を条件に設定。
class PostImage < ApplicationRecord
# 中略
validates :shop_name, presence: true
validates :image, presence: true
end
このとき、同時にマイグレーションファイルでも
null: false
を設定した方が良い。
理由は、モデルに定義しただけだとRails側で保存させないだけ。つまり、投稿フォーム経由での保存はできなくなるが、SQLから実行するとデータは保存できてしまうため。
<参考> よく使う条件
- 未入力
presence: true
- 文字数
length: { maximun: 20 } # 最大
length: { minimum: 10} # 最小
length: { in: 2..30 } # 範囲
- 一意(重複不可)
uniquness: true
- 特定のフォーマット
format: { with: 正規表現 }
2. コントローラで、エラー時の処理を設定
def create
@post_image = PostImage.new(post_image_params)
if @post_image.save
redirect_to post_images_path
else
render :new
end
end
バリデーションに引っかかると(今回は未入力なら)、saveメソッドでfalseが返る。
従い、saveメソッド自体を条件としてif文にし、elseでエラー時の処理を設定。
render :アクション名
で、同じコントローラ内のViewを表示可能
render 'コントローラ名/アクション名'
で、別コントローラのviewも表示可能
*renderとredirect_toの違い・使い分けについては、こちらの記事が分かりやすかったです
3. Viewで、エラーメッセージを表示
<% if @post_image.errors.any? %> # バリデーションエラーが発生したら以下を表示
<%= @post_image.errors.count %>件のエラーが発生しました
<% @post_image.errors.full_messages.each do |message| %>
<%= message %>
<% end %>
<% end %>
errorsは、バリデーションによるエラー内容を確認するメソッド。
any?でエラーの発生有無を判定し、full_messagesでエラー内容を出力。
*full_messagesは配列で保存されるため、eachを使用
最後に
フラッシュメッセージでも同様に、エラー時(+処理成功時も)にメッセージを表示することが可能。
今のところ、
- バリデーション:検証条件の定義&エラーメッセージ表示
- フラッシュメッセージ:成功時メッセージ表示
と認識しているが、いまいち使い分けが分かっておらず。
理解できたら更新するか別記事で上げます。