62
48

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Railsでgem無しに手軽にenumをi18nに対応させる

Posted at

ActiveRecordのenumをi18n対応させたり、formのselectでの表示に対応するためにgemが幾つかありますが、そこまで複雑なことがやりたかったわけでは無いので、手軽に自分で実装してみます。

ja.yml

モデルのattributeのi18nは通常、'activerecord.attributes.#{model_name}.#{attribute}'に定義します。例えば、Userモデルのnameに適用する場合には、

ja:
  activerecord:
    models:
      user: ユーザー
    attributes:
      user:
        name: 名前

という形で定義し、User.human_attribute_name(:name)という形でアクセスします。

それでは、例えばfemalemaleというを値を持つgenderという属性を定義します。

class User < ApplicationRecord
  enum gender: [:female, :male]
end

この場合、それぞれの値に対する国際化対応の手段は標準では用意されていません。正確には、定義の仕方は用意されていますが簡単にアクセスできる手段はありません。

定義する場合には、以下のように直接定義することは出来ません。

ja:
  activerecord:
    models:
      user: ユーザー
    attributes:
      user:
        gender: 
          female: 女性
          male: 男性
        # このネストの仕方は、複数値で形が変わる英語のような言語のための機能とバッティングします

この場合、以下のような形でモデルと同じ階層に定義してあげる必要があります。(http://guides.rubyonrails.org/i18n.html)

ja:
  activerecord:
    models:
      user: ユーザー
    attributes:
      user:
        name: 名前
        gender: 性別
      user/gender: 
        female: 女性
        male: 男性

このように定義することで、User.human_attribute_name('gender.female')のようにアクセス出来るようになります。また、この場合User.human_attribute_name('gender')も問題なく呼ぶことが出来ます。

Model

定義とアクセスの方法がわかったので、後はモデルにメソッドを追加していきます。

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)
    self.class.human_attribute_enum_value(attr_name, self[attr_name])
  end
end

これで、以下のようにアクセスすることが出来ます。

u = User.new(gender: 'female')
u.human_attribute_enum(:gender) #=> 女性

User.human_attribute_enum_value(:gender, :male) #=> 男性

selectに値を渡したい場合には

User.genders.map {|k, _| [User.human_attribute_enum_value(:gender, k), k] }.to_h #=> {"女性"=>"female","男性"=>"male"}

のように定義出来ます。或いはメソッドを更に追加しても良いかもしれません。

class ApplicationRecord < ActiveRecord::Base
  # ...

  def self.enum_options_for_select(attr_name)
    self.send(attr_name.to_s.pluralize).map {|k, _| [self.human_attribute_enum_value(attr_name, k), k] }.to_h
  end
end

User.enum_options_for_select(:gender) #=> {"女性"=>"female","男性"=>"male"}

まとめ

むやみにgemを追加していくことは避けたいと思うので、国際化対応が出来ればそれでOKくらいの用途であればこのくらい手軽な定義でも困らないんじゃないかなと思います。

62
48
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
62
48

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?