酒と泪とRubyとRailsと

Ruby on Rails と Objective-C は酒の肴です!

Railsで I18n 対応したenumを使うならenumerizeがオススメ[RubyGem]

2/15に ハレノヒ さんで開催された「Sendagaya.rb #137」に参加ました。その中でRailsの enum と 『brainspec/enumerize - GitHub』を使ったほうがいいかという話が参考になったのでメモです。


Railsのenum

Railsのenumの特徴だが機能がシンプル(既存のメソッドとのバッティング等)なのと、i18nに対応していない。 『zmbacker/enum_help - GitHub』を使うことでi18n対応は可能。

あとは @fukajun さんが最近ハマった事例。

- enumはvalueに Integer型を取ることもできるし、String型を取ることもできる
- enumにStringを使うと、DBの値が何かが一目でわかるようになる。だが、DBの容量増やIndex更新の負荷がある
- enumにIntegerを使うと、DBの容量減やIndex更新の高速化等に貢献。だが、ちょっと運用負荷がある
- rails_adminではenumのvalueをInteger前提にしている実装がある。使ってるとハマる

悩ましいところですが、enum は素直にIntegerを使ったほうが良さそう。

RubyGemsの enumerizeについて

ActiveRecord で 18n対応した enum を作るのに便利なのがRubyGem 『brainspec/enumerize - GitHub』。

それ以外にも便利な機能が幾つか実装されている。まずはベーシックなi18n対応から。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
# Migration
class CreateUsers < ActiveRecord::Migration
  def change
    create_table :users do |t|
      t.string :sex
      t.string :role

      t.timestamps
    end
  end
end

# Model:
class User < ActiveRecord::Base
  extend Enumerize

  enumerize :sex, in: { mail: 1, female: 2}
end

# I18n:
en:
  enumerize:
    user:
      sex:
        male: "Male"
        female: "Female"

スコープ的な使い方をすることもできます。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class User < ActiveRecord::Base
  extend Enumerize
  enumerize :sex, :in => [:male, :female], scope: true
  enumerize :status, :in => { active: 1, blocked: 2 }, scope: :having_status
end

User.with_sex(:female)
# SELECT "users".* FROM "users" WHERE "users"."sex" IN ('female')

User.without_sex(:male)
# SELECT "users".* FROM "users" WHERE "users"."sex" NOT IN ('male')

User.having_status(:blocked).with_sex(:male, :female)
# SELECT "users".* FROM "users" WHERE "users"."status" IN (2) AND "users"."sex" IN ('male', 'female')

formとかにも簡単に使えます。

1
2
3
<%= form_for @user do |f| %>
  <%= f.select :sex, User.sex.options %>
<% end %>

共通的に値を扱うクラスを作ることもできる。

1
2
3
4
5
6
7
8
9
10
11
12
13
module PersonEnumerations
  extend Enumerize

  enumerize :sex, in: %w[male female]
end

class Person
  include PersonEnumerations
end

class User
  include PersonEnumerations
end

SimpleFormやRSpecの対応も充実しており、実際に使いやすさが追求されているのが好感を持てます。 個人的には、Railsのenumの機能だけで事足りる場合はそちらを使い、enumerizeは便利な機能やi18n対応したい場合に使うようにしたいと思います!

brainspec/enumerize - GitHub

あとがき

懇親会で六本木の英国発ブリュードッグ(BrewDog)に行きました。珍しいビールの話を聞けて面白かった!次回も楽しみ!

おすすめの書籍