This page looks best with JavaScript enabled
⚠️

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

 ·   ·  ☕ 3 分で読めます
✏️

はじめに

image.png
こんな感じのフォームを作ります。

環境

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

作成法

enumの設定

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

1
2
3
4
5
6
7
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
1
2
3
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に変換されている。

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

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
user.privacy
=> "closed"
user.privacy = 0
=> 0
user.privacy
=> "published"
user.privacy = :closed
=> :closed
user.privacy
=> "closed"

i18nの設定

1
2
gem 'rails-i18n'
gem 'enum_help'

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

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
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配下に日本語化用のファイルを用意します。(ファイルの場所や名前は自由)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
ja:
  activerecord:
    models:
      user: ユーザー
    attributes:
      id: ID
      created_at: 作成日時
      updated_at: 更新日時
      user:
        name: 名前
        description: 自己紹介
        privacy: 公開設定
  enums:
    user:
      privacy:
        published: 公開
        closed: 非公開

formの作成

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
= 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 プロパティ名, 選択肢の配列とすればいいので、

1
  = f.select :privacy, [['公開', 0], ['非公開', 1]]

これでも可能ですが、なんか嫌です。モデルと関連付けたい。
そこで、gemの出番です。'enum_help'によってそれぞれ以下のようなインスタンスメソッドとクラスメソッドが使えるようになります。

1
2
3
4
user.privacy_i18n
=> "公開"
User.privacies_i18n
=> {"published"=>"公開", "closed"=>"非公開"}

これを利用して[[表示される選択肢, 渡される値], [表示される選択肢, 渡される値]]の形の配列に置き換えます。

1
2
3
4
User.privacies_i18n.map { |k, v| [v, k] }
=> [["公開", "published"], ["非公開", "closed"]]
User.privacies_i18n.invert.to_a
=> [["公開", "published"], ["非公開", "closed"]]

どちらも同じですが、後者の方が文字数が少なくシンプルかなと思います。

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

リンク

Enums | Active Record クエリインターフェイス - Rails ガイド
Rails国際化 (i18n) API - Rails ガイド

Share on

END
END
@aiandrox

 
目次