【Rails】enum_helpを用いてi18n対応セレクトボックスを作成

##はじめに
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/322882/bc3ee11d-cf3a-8ba6-52bd-9f5db8b564db.png)
こんな感じのフォームを作ります。

### 環境
ruby 2.5.3
Rails 5.2.4.2
enum_help (0.0.17)
rails-i18n (5.1.3)

## 作成法
### enumの設定

```models/user.rb
class User < ApplicationRecord
  validates :name, presence: true, length: { maximum: 30 }
  validates :description, length: { maximum: 300 }
  validates :privacy, presence: true

  enum privacy: { published: 0, closed: 1 }
end
```

booleanにしていないのは、今後限定公開などの機能を追加することを想定しているためです。
このようにenumを設定することで、データベースで数値として扱っている値を、Railsでは文字列として擬似的に扱うことができます。

```terminal
User.find_by(privacy: :published)
  User Load (4.2ms)  SELECT  `users`.* FROM `users` WHERE `users`.`privacy` = 0 LIMIT 1
=> #<User id: 1, name: "名前", description: "詳細", privacy: "published", created_at: "2020-04-10 12:41:31", updated_at: "2020-04-10 12:41:31">
```

↑SQLでは`` `privacy` = 0 ``に変換されている。

また、この値は文字列でもシンボルでも指定できます。

```rb
user.privacy
=> "closed"
user.privacy = 0
=> 0
user.privacy
=> "published"
user.privacy = :closed
=> :closed
user.privacy
=> "closed"
```

### i18nの設定

```:Gemfile
gem 'rails-i18n'
gem 'enum_help'
```

必要なgemを記述して、`$ bundle install`でインストールします。
そして、application.rbに以下の設定を追加します。

```config/application.rb
module TestApp
  class Application < Rails::Application
    # 言語・タイムゾーンを日本に設定
    config.i18n.default_locale = :ja
    config.time_zone = 'Tokyo'
    config.active_record.default_timezone = :local
    # config/locales/配下の全てのrb, ymlファイルを読み込み対象とする
    config.i18n.load_path += Dir[Rails.root.join('config', 'locales', '**', '*.{rb,yml}').to_s]
  end
end
```

`config/locales`配下に日本語化用のファイルを用意します。（ファイルの場所や名前は自由）

```config/locales/models/ja.yml
ja:
  activerecord:
    models:
      user: ユーザー
    attributes:
      id: ID
      created_at: 作成日時
      updated_at: 更新日時
      user:
        name: 名前
        description: 自己紹介
        privacy: 公開設定
  enums:
    user:
      privacy:
        published: 公開
        closed: 非公開
```

### formの作成

```form.html.slim
= form_with model: @user, local: true do |f|
  = f.label :name
  = f.text_field :name
  br
  = f.label :description
  = f.text_area :description
  br
  = f.label :privacy
  = f.select :privacy, User.privacies_i18n.invert
  br
  = f.submit
```

こんな感じです。ポイントはセレクトボックスの値です。
`= f.select プロパティ名, 選択肢の配列`とすればいいので、

```rb
  = f.select :privacy, [['公開', 0], ['非公開', 1]]
```
これでも可能ですが、なんか嫌です。モデルと関連付けたい。
そこで、gemの出番です。`'enum_help'`によってそれぞれ以下のようなインスタンスメソッドとクラスメソッドが使えるようになります。

```rb
user.privacy_i18n
=> "公開"
User.privacies_i18n
=> {"published"=>"公開", "closed"=>"非公開"}
```
これを利用して`[[表示される選択肢, 渡される値], [表示される選択肢, 渡される値]]`の形の配列に置き換えます。

```rb
User.privacies_i18n.map { |k, v| [v, k] }
=> [["公開", "published"], ["非公開", "closed"]]
User.privacies_i18n.invert.to_a
=> [["公開", "published"], ["非公開", "closed"]]
```
どちらも同じですが、後者の方が文字数が少なくシンプルかなと思います。

（追記）
これだけ書いておいて何ですが、配列に変更する必要はありませんでした。ハッシュのままでも行けました。
ということで、`User.privacies_i18n.invert`が最短です。
そして[五年前の記事](https://qiita.com/rinkun/items/d41cd744f033a33cda2c)で既に言及していたので、ここに恥を晒しておきます。

## リンク

[Enums | Active Record クエリインターフェイス - Railsガイド](https://railsguides.jp/active_record_querying.html#enums)
[Rails 国際化 (i18n) API - Railsガイド](https://railsguides.jp/i18n.html)