いわりょのBlog

IT関連で学んだことを書いていきます。

rails フォームでよく使われるエラーメッセージパーシャルなど作成

実現すること

フォームに何も入力されてない状態で投稿ボタン押すなどするとアラートが出るやつです。

方法

例としてProductモデルを使います。バリデーションは下記の通り↓

product.rb

class Product < ApplicationRecord

    validates :name,        presence: true, length:{ maximum: 50}
    validates :price,       presence: true, length:{ maximum: 20}, format: /\A[0-9]+\z/
    validates :description, presence: true, length:{ maximum: 200}
    validates :picture,     presence: true
end

空なし、文字数制限、フォーマットの指定などを設定しています。
これでモデル(model)でバリデーションエラーが発生した場合に、model の errorsにエラーメッセージが設定されます。


コントローラー↓

products_controller.rb

def create
    @product = Product.new(product_params)
    if @product.save
      (省略)
    else
 #バリデーションエラーがあればフォームに戻る
      render 'new'
    end
  end


パーシャル作成

_error_messages.html.erb

<% if object.errors.any? %>
  <div id="error_explanation">
    <div class="alert alert-danger">
      <%= object.errors.count %>つのエラー! 入力に誤りがあります。
    </div>
    <ul>
    <% object.errors.full_messages.each do |msg| %>
      <li><%= msg %></li>
    <% end %>
    </ul>
  </div>
<% end %>

renderでフォームにエラーメッセージのパーシャルを追加
今回はform_forを使っています。

     <div class="form">
    <%= form_for(@product) do|f| %>

    #error_messages.html.erbを呼び出す
    <%= render'error_messages',object: f.object %>

    <div class="form-group">
        <%= f.label "商品名" %>
        <%= f.text_field :name ,class: 'form-control' %>
    </div>

    <div class="form-group">
        <%= f.label "定価" %>
        <%= f.text_field :price ,class: 'form-control' %>
    </div>

    (中略)

    <%= f.submit '投稿する', class: "submit-btn" %>
    <% end %>
    </div>

コントローラーの動きの通りバリデーションエラーがでた場合には、フォーム画面に戻ります。
そこでif文でエラーがあると認識され、error_explanation要素が表示されます。object.errorsには発生したエラーが含まれているので、object.errors.countとすれば「エラーの数」、object.errors.full_messagesはエラーメッセージを配列で持っているので、eachメソッドで順番に表示しています。

メッセージを日本語化したい場合は、こちらの記事を参考に設定しましょう。
Railsのバリデーションエラーのメッセージの日本語化 - Qiita

設定ができたらProductモデル用のja.ymlを作成

ja.yml

ja:
  activerecord:
    models:
      product: 商品
    attributes:
      product:
        id: ID
        created_at: 登録日時
        updated_at: 更新日時
        name: 商品名
        price: 定価
        description: 説明
        picture: 画像

あとはエラーメッセージの見た目を整えます。

//Alert
#error_explanation {
    color: red;
    ul {
      list-style-position: inside;
      color: red;
      margin: 0 0 30px 0;
    }
}

.field_with_errors {
    .form-control {
        border-color: #ebccd1;
    }
}

.alert {
    padding: 15px;
    margin-bottom: 20px;
    border: 1px solid transparent;
    border-radius: 4px;
}
.alert-danger {
    color: #a94442;
    background-color: #f2dede;
    border-color: #ebccd1;
}

form_forを使っていて、バリデーションエラーが発生すると全てのフィールドにfield_with_errorsを追加するのでその時にそれぞれのフォームの枠線を赤っぽくしています。


これでフォームで入力なし、文字の制限を超える、フォーマットが違うなどのエラーを拾ってメッセージが表示されるようになります!