はじめに
ActiveRecordのenumで定義した要素をセレクトボックスを作りたいときの用法用量です。 ※gemを追加しても同等のことができますがコード量も少ないので自作で進めます。
i18n(Internationalization)について
モデルのattributeのi18nは通常、'activerecord.attributes.#{model_name}.#{attribute}'に定義します。 例えば、Userモデルのnameに適用する場合には、config/locales/ja/activerecord/user.ymlのようなファイルを作成します。
ja: activerecord: models: user: ユーザー attributes: user: name: 名前
取得時は
User.human_attribute_name(:name)
という形でアクセスします。
enumを管理する場合
本題に移ります。
今回は例として、Userがgenderという属性を定義しているとします。 genderにはfemaleとmaleというを値を持たせます。 - female(女性) - male(男性)
class User < ApplicationRecord enum gender: { female: 0, male: 1 } end
この後にしがちな(想定しそうな)yamlの定義の仕方としては下記のような記述でしょうか。
ja: activerecord: models: user: ユーザー attributes: user: gender: female: 女性 male: 男性
このようにuesr > gender > attributeの順にネストして直接定義することは出来ません。
この場合、以下のような形でモデルと同じ階層に定義してあげる必要があります。(http://guides.rubyonrails.org/i18n.html)
ja: activerecord: models: user: ユーザー attributes: user: name: 名前 gender: 性別 user/gender: # model/attribute female: 女性 male: 男性
定義方法に注目してください。
これにより下記のようなアクセスが可能になります。
User.human_attribute_name('gender.female') # => 女性 User.human_attribute_name('gender') # => 性別 # こちらも問題なく呼べる
Modelに便利メソッドを定義
基底モデルにenum専用のメソッドを追加していきます。 変更するファイルはapp/models/application_record.rbです。
class ApplicationRecord < ActiveRecord::Base self.abstract_class = true def self.human_attribute_enum_value(attr_name, value) human_attribute_name("#{attr_name}.#{value}") end def human_attribute_enum(attr_name) class.human_attribute_enum_value(attr_name, [attr_name]) end end
これで、以下のようにアクセスすることが出来ます。
user = User.new(gender: :female) user.human_attribute_enum(:gender) #=> 女性 User.human_attribute_enum_value(:gender, :male) #=> 男性
form用のメソッドも追加
最後にselectに値を渡していきます。 特にメソッドを使わなくともこのように書くことも出来ます。
app/views/users/_form.html.slim
# テンプレートはslimを使用 # app/views/users/_form.html.slimの呼び出し元でUserオブジェクトのインスタンスをローカル変数で定義してあります = form_for user do |f| = f.select :gender, User.genders.map {|k, _| [User.human_attribute_enum_value(:gender, k), k] }.to_h #=> {"女性"=>"female","男性"=>"male"}
メソッドを追加して記述するとすると下記のようになります。
app/models/application_record.rb
class ApplicationRecord < ActiveRecord::Base # ... def self.enum_options_for_select(attr_name) send(attr_name.to_s.pluralize).map {|k, _| [human_attribute_enum_value(attr_name, k), k] } end end
※ このように使います。
User.enum_options_for_select(:gender) #=> {"女性"=>"female","男性"=>"male"}
最後にformに追加します。
app/views/users/_form.html.slim
= form_for @user do |f| = f.select :gender, User.enum_options_for_select(:gender)
これで [["女性", "female"], ["男性", "male"]]の組み合わせのセレクトボックスを生成することができました!