【Rails】validationのエラーメッセージを個別に表示する方法


この記事のゴール

この記事では公式リファレンスを参照し、以下の画像のようにValidationのエラーメッセージを各フォームの近くに個別に表示する方法を記載しております。

環境

この記事では以下の環境にて実装を行なっております。

  • ruby 2.6.5p114 (2019-10-01 revision 67812)
  • Rails 6.0.3.4
  • Bundler version 2.1.4

実装過程

前提

Terminal
rails g scaffold Post title:string content:text

今回はRailsでscaffoldを使用しPostモデルを作成。
Postモデルは「string型のtitleカラム」と「text型のcontentカラム」を持っています。

post.rb
class Post < ApplicationRecord
  validates :title, presence: true
  validates :title, length: { minimum: 2, maximum: 30 }
  validates :content, presence: true
end

それぞれのカラムは以下のvalidationを持っています。

title(タイトル)
  • 入力必須
  • タイトルは2文字以上30文字以下で入力
content(内容)
  • 入力必須

Validationエラーをまとめて表示する(よくある表示方法)


scaffoldでは上記のように、デフォルトでvalidationのエラーメッセージがまとめて表示されるようになっています。
普段の実装でもこのような表示方法を採用している方は多いと思います。

上記のエラーメッセージは以下のように定義しています。

app/views/post/_form.html.haml
  - if post.errors.any?
    #error_explanation
      %h2
        = pluralize(post.errors.count, "error")
        prohibited this post from being saved:
      %ul
        - post.errors.full_messages.each do |message|
          %li= message

① まず変数postに対しerrorsメソッドでエラー文に関するハッシュを取得します。

② その値に対しfull_messagesメソッドを使用することによりエラーメッセージを配列で取得します。

・full_messagesメソッド

全てのエラーメッセージを配列で取得するメソッド

③ 配列で取得した値にeachメソッドを使用することでエラー文をそれぞれ表示します。

Validationエラーを個別に表示する(今回の主題)


上記のエラーメッセージは以下のように定義しています。

app/views/post/_form.html.haml
= form_with(model: post, local: true) do |form|
  .field
    = form.label :title
    = form.text_field :title

    //以下がtitleカラムに関するエラーメッセージの表示
    - if post.errors.include?(:title)
      %p= post.errors.full_messages_for(:title).first

  .field
    = form.label :content
    = form.text_area :content

    //以下がcontentカラムに関するエラーメッセージの表示
    - if post.errors.include?(:content)
      %p= post.errors.full_messages_for(:content).first

  .actions
    = form.submit

① まずinclude?(attribute)メソッドを使用し、引数に入っているカラムに関するエラーが存在するかを判別します。
include?(attribute)メソッドはkey?(attribute)メソッドやhas_key?(attribute)メソッドでも代用可能です。

・include?(attribute)メソッド
・key?(attribute)メソッド
・has_key?(attribute)メソッド

errors.messagesで得た配列の中に、引数内のカラムに関するエラーが存在する
場合はtrueを返し、存在しない場合はfalseを返すメソッド

② エラーメッセージが存在する場合は、full_messages_for(attribute)メソッドで引数内のカラムに関するエラーを配列で取得します。

・full_messages_for(attribute)メソッド

引数内のカラムに関するエラーメッセージを配列で取得するメソッド

③ 上記で取得した配列にfirstを使用することでエラー文を個別に表示します。

UIを整える

① semantic-uiをインストールする

Gemfileに以下を追加し、bundle installします。

Gemfile
gem 'semantic-ui-sass'

② semantic-uiを使用できるようにする

application.scssに以下を追加します。

app/assets/stylesheets/application.scss
 @import "semantic-ui"

これでsemantic-uiを使えるようになったので、エラーメッセージのスタイルを整えていきます。

③ semantic-uiでスタイル調整

semantic-uiを使用し、以下のようにクラスを使ってスタイルを当てたら上記のようなエラーメッセージを表示することができます。

app/views/post/_form.html.haml
= form_with(model: post, local: true) do |form|
  .ui.form
    .field.required
      = form.label :title, 'タイトル'
      = form.text_field :title
      - if post.errors.include?(:title)
        %p.ui.pointing.red.basic.label
          %i.attention.circle.icon
          = post.errors.full_messages_for(:title).first
    .field.required
      = form.label :content, '内容'
      = form.text_area :content
      - if post.errors.include?(:content)
        %p.ui.pointing.red.basic.label
          %i.attention.circle.icon
          = post.errors.full_messages_for(:content).first
    .actions
      = form.submit '保存', class: 'ui primary button'

参考文献