【Rails】バリデーションの設定〜エラーメッセージ表示までの手順


バリデーションとは

dbへデータを保存する際に、そのデータが意図したものかどうか検証する仕組み。
例)何かを投稿するときに名前を入力必須にする、パスワードの文字数は4文字以上、等々。

目標

インスタのような画像投稿SNSで、画像を投稿する際、未入力項目があれば、エラーメッセージを表示できるようにする。
モデルとカラムは以下の前提。
- モデル:PostImage
- カラム:shop_name、image

設定手順

<おおまかな流れ>
1. モデルで、バリデーションの条件を設定
2. コントローラで、エラー時の処理を設定
3. 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で、エラーメッセージを表示

views/post_images/new.html.erb
<% 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を使用

最後に

フラッシュメッセージでも同様に、エラー時(+処理成功時も)にメッセージを表示することが可能。

今のところ、
- バリデーション:検証条件の定義&エラーメッセージ表示
- フラッシュメッセージ:成功時メッセージ表示
と認識しているが、いまいち使い分けが分かっておらず。

理解できたら更新するか別記事で上げます。