🎲

【Rails】gem Enumerize で enum を扱う

2022/04/21に公開

はじめに

gem Enumerize を使って enum を扱う機会がちょこちょこあったので、
書き方について少しまとめたいと思います。

Enumerize

この記事に書いてあることのほとんどはここに書いてあります🤭
https://github.com/brainspec/enumerize

Enumerize を使った書き方

私が遭遇したケースと書き方をあげていきます。

基本

class User
  extend Enumerize

  enumerize :role, in: [:user, :admin]
end

このように、モデルに定義することで enum として扱うことができます。

カスタム値で属性の値を保存したい

:in オプションでハッシュを渡すことで
カスタム値(integer等)を使って列挙型の属性値を保存することが可能。

class User < ActiveRecord::Base
  extend Enumerize

  enumerize :role, in: {:user => 1, :admin => 2}
end
user = User.new
user.role = :user
user.role #=> 'user'
user.role_value #=> 1

User.role.find_value(:user).value #=> 1
User.role.find_value(:admin).value #=> 2

attribute_value とすることで定義した値が取得できます。

テキスト値の配列を取得したい

User.status.values
=> ['student', 'employed', 'retired']

テキスト値からキーの配列を取得したい

User.status.values
=> ['student', 'employed', 'retired']

i18n 対応

class Person
  extend Enumerize
  extend ActiveModel::Naming # plain Ruby オブジェクトで I18n を使用したい場合

  enumerize :status, in: %w[student employed retired], i18n_scope: "status"
end

# localization file
en:
  status:
    student: "Student"
    employed: "Employed"
    retired: "Retiree"

i18n に対応した属性値

@user.status = :student
@user.status_text # => 'Student'

属性値の配列

User.status.values # => ['student', 'employed', 'retired']

i18n に対応した属性値の配列

User.status.values.collect(&:text) # => ['Student', 'Employed', 'Retiree']

値ごとに集計したい

class Customer < ActiveRecord::Base
  extend Enumerize
  enumerize :sex, :in => [:male, :female], scope: true
end
customer_counts = Customer.group(:sex).count # => {"male"=>23, "female"=>15}
customer_counts["male"] # => 23
customer_counts["female"] # => 15

Enum 値を共通化したい

同じ属性を複数箇所で使いたい場合は、
Module 化して、各class で include する。

module StatusEnumerations
  extend Enumerize

  enumerize :status, in: [:new, :doing, :done]
end

class Hoge
  include StatusEnumerations
end

class Fuga
  include StatusEnumerations
end

私の場合は、
同じ属性の値を他のクラスで使いたい
かつ
日本語のテキストから値を更新したい
というケースだったため
モジュールにメソッドを定義して共通化することにしました。
(以下はあくまでわかりやすくしたものです)

module StatusEnumerations
  extend Enumerize

  enumerize :status, in: [:new, :doing, :done]

  def convert_status_value(value)
    status = {
      '新規' => 'new',
      '着手中' => 'doing',
      '完了' => 'done'
    }
    status[value]
  end
end

おわりに

直近で遭遇した Enumerize を使った書き方についてまとめてみました。
まだまだできることはたくさんあるので、気になる人は調べてみてください。
https://github.com/brainspec/enumerize

Discussion