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

# 目標
![ezgif.com-video-to-gif.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/579893/b945ea85-749b-f032-e4db-c7b27a6552a0.gif)
# 開発環境
・Ruby: 2.5.7
・Rails: 5.2.4
・Vagrant: 2.2.7
・VirtualBox: 6.1
・OS: macOS Catalina

# 前提

下記実装済み。

・[Slim導入](https://qiita.com/matsubishi5/items/b639ffddecc626856039)
・[投稿機能実装](https://qiita.com/matsubishi5/items/1a5aeab651b5822d1f2c)

# 実装

## 1.`application.rb`を編集

```ruby:application.rb
module Bookers2Debug
  class Application < Rails::Application
    config.load_defaults 5.2

    # 追記
    config.action_view.field_error_proc = Proc.new do |html_tag, instance|
      if instance.kind_of?(ActionView::Helpers::Tags::Label)
        html_tag.html_safe
      else
        class_name = instance.object.class.name.underscore
        method_name = instance.instance_variable_get(:@method_name)
        "<div class=\"has-error\">#{html_tag}
          <span class=\"help-block\">
            #{I18n.t("activerecord.attributes.#{class_name}.#{method_name}")}
            #{instance.error_message.first}
          </span>
        </div>".html_safe
      end
    end
  end
end
```

### 【解説】

#### ① エラーが出ていない場合はHTMLをそのまま表示する。

```ruby
if instance.kind_of?(ActionView::Helpers::Tags::Label)
  html_tag.html_safe
```

#### ② エラーが出ている場合はエラーメッセージをフォームの下に表示する。

```ruby
else
  class_name = instance.object.class.name.underscore
  method_name = instance.instance_variable_get(:@method_name)
  "<div class=\"has-error\">#{html_tag}
    <span class=\"help-block\">
      #{I18n.t("activerecord.attributes.#{class_name}.#{method_name}")}
      #{instance.error_message.first}
    </span>
  </div>".html_safe
```

**◎ インスタンスのクラス名を変数へ代入**

```ruby
class_name = instance.object.class.name.underscore
```

**◎ インスタンスのメソッド名を変数へ代入**

```ruby
method_name = instance.instance_variable_get(:@method_name)
```

**◎ エラーメッセージ部分のHTMLを作成する。**

```ruby
"<div class=\"has-error\">#{html_tag}
  <span class=\"help-block\">
    #{I18n.t("activerecord.attributes.#{class_name}.#{method_name}")}
    #{instance.error_message.first}
  </span>
</div>".html_safe
```

「タイトルを入力してください」と表示する場合、
`#{I18n.t("activerecord.attributes.#{class_name}.#{method_name}")}`が、
「タイトル」にあたる部分で、
`#{instance.error_message.first}`が、
「を入力してください」にあたる部分になる。

## 2.エラーメッセージを日本語化

### ① Gemを導入

```ruby:Gemfile
# 追記
gem 'rails-i18n'
```

```terminal:ターミナル
$ bundle
```

### ② `application.rb`を編集

```ruby:application.rb
module Bookers2Debug
  class Application < Rails::Application
    config.load_defaults 5.2
    config.i18n.default_locale = :ja # 追記

    config.action_view.field_error_proc = Proc.new do |html_tag, instance|
      if instance.kind_of?(ActionView::Helpers::Tags::Label)
        html_tag.html_safe
      else
        class_name = instance.object.class.name.underscore
        method_name = instance.instance_variable_get(:@method_name)
        "<div class=\"has-error\">#{html_tag}
          <span class=\"help-block\">
            #{I18n.t("activerecord.attributes.#{class_name}.#{method_name}")}
            #{instance.error_message.first}
          </span>
        </div>".html_safe
      end
    end
  end
end
```

### ③ `ja.yml`を作成し、編集

```terminal:ターミナル
$ touch config/locales/ja.yml
```

```yml:ja.yml
ja:
  activerecord:
    attributes:
      book:
        title: タイトル
        body: 本文
```