errorメッセージを個別で出したい

色々と調べながらやってるうちに知らない間にerrorメッセージを出せるようになってしまったが、やったことに自分の頭がついていっていないので、落ち着いてまとめてみる。

エラーメッセージ用のテンプレートの作成

まずはじめに全てのエラーメッセージを配列で取得します。が、エラーメッセージ用の部分テンプレートを作成するのが先です。いろいろなところで使うので、viewに書き込むと直すのが手間になってしまいます。views/shared/_error_messages.html.erbとしておきましょう。

<% if model.errors.any? %>
  <div class="alert alert-warning">
    <ul>
      <% model.errors.full_messages.each do |message| %>
        <li><%= message %></li>
      <% end %>
    </ul>
  </div>
<% end %>

さて、上のように書くことで、エラーメッセージを配列で取得でき、複数のエラーメッセージがある可能性がある(自分で作っていれば)ので、eachを使って、全て取得します。一行ずつ丁寧にみていきます。

1行目 <% if model.errors.any? %>

<% if model.errors.any? %>

errors.any?はエラーがあるかどうかの真偽を出してくれるメソッドです。じゃあ、modelは?というと、呼び出す先で指定しているものになります。呼び出し先をviews/users/new.html.erbとでもしましょう。

<%= form_with model: @user, local: true do |f| %>
  <%= render 'shared/error_messages', model: f.object %>
...

<%= render 'shared/error_messages', model: f.object %>の部分で呼び出しをしていて、model: f.objectmodelの部分が、<% if model.errors.any? %>のmodelと対応しています。では、f.objectってなんだろう?ということで調べていきます。

model: f.objectとは

fはフォームビルダー変数といい、

<%= form_with model: @user, local: true do |f| %>

form_withで生成された|f|の部分です。このフォームビルダー変数には様々なメソッドがあり、text_field(一行のテキスト投稿フォーム)やselect(選択肢を作成)など様々ある。f.objectには、入力したデータが入っています。つまり、model: @userの情報をもっていることになるので、userコントローラーのnewアクションとつながっていることになる。かなり遠いところまで行くけど、そういうことみたい。

4行目 <% model.errors.full_messages.each do |message| %>

まず、はじめのmodelには、呼び出し先の

<%= form_with model: @user, local: true do |f| %>

の@userが代入されます。そして、errorsメソッドで@userの持っているエラーを表示してくれ、full_messagesでエラーの文章のみを配列で表示してくれます。そして、each do |message|でエラーの配列を一つ一つ処理してくれる、というようになっているようです。

これでエラーメッセージが個別で出る動きが分かった。難しい。

参考

https://yama2-0506.hatenablog.com/entry/2020/12/11/083007 https://qiita.com/ryuuuuuuuuuu/items/1a1e53d062bff774d88a