Rails6 のちょい足しな新機能を試す９(エラーメッセージのフォーマット編）

# はじめに

Rails 6 に追加されそうな新機能を試す第９段。 今回のちょい足し機能は、 `full message` 編です。
ymlファイルで指定できるエラーフォーマットが拡張されてます。

記載時点では、Rails は 6.0.0.rc1 です。　`gem install rails --prerelease` でインストールできます。

```shell
$  rails --version
Rails 6.0.0.rc1
```

# プロジェクトを作成する

rails プロジェクトを作成します。

```shell
$ rails new sandbox6_0_0rc1
```

# model を作る

```shell
$ cd sandbox6_0_0rc1
$ bin/rails g model User name email
$ bin/rails db:create db:migrate
```

# model に validation を追加する

```ruby:app/models/user.rb
class User < ApplicationRecord
  validates :name, presence: true
  validates :email, presence: true
end
```

# 何もymlファイルに指定がないとき

何もymlファイルに指定がないときには、今までと同じ `Name can't be blank` と `Email can't be blank` になります。

```ruby
$ bin/rails c
Running via Spring preloader in process 653
Loading development environment (Rails 6.0.0.rc1)
irb(main):001:0> user = User.new
=> #<User id: nil, name: nil, email: nil, created_at: nil, updated_at: nil>
irb(main):002:0> user.validate
=> false
irb(main):003:0> user.errors.full_messages
=> ["Name can't be blank", "Email can't be blank"]
irb(mail):004:0> exit
```

# yml ファイルでエラーフォーマットを指定

エラーメッセージのフォーマット全体を指定してみます。

```yaml:config/locales/en.yml
en:
  errors:
    format: '%{message}'
```

指定されたフォーマット (`can't be blank` だけ) にエラーメッセージが変わります。

```ruby
$ bin/rails c
Running via Spring preloader in process 696
Loading development environment (Rails 6.0.0.rc1)
irb(main):001:0> user = User.new
=> #<User id: nil, name: nil, email: nil, created_at: nil, updated_at: nil>
irb(main):002:0> user.validate
=> false
irb(main):003:0> user.errors.full_messages
=> ["can't be blank", "can't be blank"]
irb(main):004:0> exit
```

実はここまでは、Rails 5.2.3でも同じです。

# yml ファイルで model レベルでエラーフォーマットを指定

ここからが、Rails6のちょい足しです。
エラーメッセージのフォーマットを model レベルで指定してみます。

```yaml:config/locales/en.yml
en:
  errors:
    format: '%{message}'
  activerecord:
    errors:
      models:
        user:
          format: '%{attribute} : %{message}'
```

では、エラーメッセージを確認してみましょう。
このとき、 `ActiveModel::Errors.i18n_customize_full_message = true` にします。

```ruby
$ bin/rails c
Running via Spring preloader in process 1338
Loading development environment (Rails 6.0.0.rc1)
irb(main):001:0> ActiveModel::Errors.i18n_customize_full_message = true
=> true
irb(main):002:0> user = User.new
=> #<User id: nil, name: nil, email: nil, created_at: nil, updated_at: nil>
irb(main):003:0> user.validate
=> false
irb(main):004:0> user.errors.full_messages
=> ["Name : can't be blank", "Email : can't be blank"]
irb(main):007:0> exit
```

なお `ActiveModel::Errors.i18n_customize_full_message` はデフォルトでは、`false` です。
`ActiveModel::Errors.i18n_customize_full_message = false` のときは、modelレベルの設定は無視されます。

```ruby
$ bin/rails c
Running via Spring preloader in process 1343
Loading development environment (Rails 6.0.0.rc1)
irb(main):001:0> ActiveModel::Errors.i18n_customize_full_message
=> false
irb(main):002:0> user = User.new
=> #<User id: nil, name: nil, email: nil, created_at: nil, updated_at: nil>
irb(main):003:0> user.validate
=> false
irb(main):004:0> user.errors.full_messages
=> ["can't be blank", "can't be blank"]
irb(main):005:0> exit
```

# yml ファイルで attribute レベルでエラーフォーマットを指定

今度は、attribute レベルでエラーフォーマットを指定してみます。

```yaml:config/locales/en.yml
en:
  errors:
    format: '%{message}'
  activerecord:
    errors:
      models:
        user:
          format: '%{attribute} : %{message}'
          attributes:
            name:
              format: '%{message} - %{attribute}'
```

では、試してみましょう。
`name` は、 `'%{message} - %{attribute}'` のフォーマットが適用され
`email` は、 `'%{attribute} : %{message}'` のフォーマットが適用されます。

```ruby
$ bin/rails c
Running via Spring preloader in process 1383
Loading development environment (Rails 6.0.0.rc1)
irb(main):001:0> ActiveModel::Errors.i18n_customize_full_message = true
=> true
irb(main):002:0> user = User.new
=> #<User id: nil, name: nil, email: nil, created_at: nil, updated_at: nil>
irb(main):003:0> user.validate
=> false
irb(main):004:0> user.errors.full_messages
=> ["can't be blank - Name", "Email : can't be blank"]
irb(main):005:0>
```

# `i18n_customize_full_message` の設定

今回、irb の中で動的に設定しましたが、 `i18n_customize_full_message` は、 config ファイルで設定できます。

```ruby:config/application.rb
module Sandbox600rc1
  class Application < Rails::Application
     ...
    config.active_model.i18n_customize_full_message = true
  end
end
```

# 参考情報
* [What is new in Rails 6.0](https://bogdanvlviv.com/posts/ruby/rails/what-is-new-in-rails-6_0.html)
* [Allow to override the full_message error format](https://github.com/rails/rails/pull/32956)
* [Rename `i18n_full_message` config option to `i18n_customize_full_message`](https://github.com/rails/rails/commit/d8ba2f7c5670f5b2ef1486c9a3fb3e69fc514989)