Railsにおけるenum

Enum」は「列挙型」のこと。 この列挙型を扱う機能としてRuby on Rails4.1からActiveRecord :: Enumと言うモジュールが追加となった。

この機能は、モデルの数値カラムに対して文字列による名前定義が可能。また、データ操作用の便利なメソッドも提供してくれる。enumは主に以下の時に、使われる。

  • 頻繁に更新が発生する
  • 名前定義が中規模〜大規模
  • 複数モデルで利用されている

モデルの中で、has_manyやvalidatesがあるところに設置。基本的な定義は以下の通り。

enum public_flag: {unpublished: 0, published: 1}


これで定義したモデルのオブジェクトに「unpublished」「published」というメソッド、そのインスタンスについて「unpublished!」「published!」「unpublished?」「published?」というメソッドが使えるようになる。どうなるかというと・・・

Article.published
=>公開された記事がすべて返される。

Article.unpublished
=>非公開記事がすべて返される。

@article = Article.find(1)
@article.published?
=> true  # この記事が公開されているのでtrueが返る。

@article.unpublished?
=> false

#記事を非公開にする。「!」をつけることで更新される。
@article.unpublished!
@article.unpublished?
=> true

# 非公開に変えられたので、falseになる。
@article.published?
=> false


prefix(接頭辞)suffix(接尾辞)を使う

class Event < ActiveRecord::Base
  enum status: [:active, :inactive, :free], _prefix: true
  enum payment_type: [:cash, :credit_card, :free], _prefix: true
end


_prefix: true

enum 行の後ろに prefix: true を付与。 :free は、 enum status と enum payment_type のどちらにも存在する値だが、 prefix を付与することで重複エラーにはならない。結果、次のようになる。

# 頭に status_ を付与
> event.status_inactive! # 更新(UPDATE)
> event.status_inactive? # true
> event.status_active? # false

# 頭に payment_type_ を付与
> event.payment_type_free! # 更新(UPDATE)
> event.payment_type_free? # true
> event.payment_type_cash? # false
> event.payment_type_credit_card? # false


# 接頭辞なしはエラーになる。注意!!
> event.active?
Traceback (most recent call last):
        1: from (irb):11
NoMethodError (undefined method `active?' for #<Conversation:0x00007ff78097c910>)

# オブジェクトにも適用できる
Event.payment_type_free
=> 支払いタイプがfreeのイベントが全て返る。


_suffix: true

接尾辞。以下の通り。

class Conversation < ActiveRecord::Base
  enum status: [:active, :archived], _suffix: true
  enum comments_status: [:active, :inactive], _suffix: true
end

で、どうなるかと言うと・・・

# お尻に _status を付与
> conversation.archived_status! # 更新(UPDATE)
> conversation.archived_status? # true
> conversation.active_status? # false

# お尻に _comments_status を付与
> conversation.active_comments_status! # 更新(UPDATE)
> conversation.active_comments_status? # true
> conversation.inactive_comments_status? # false

# 接尾辞なしはエラーになる
> conversation.active?
Traceback (most recent call last):
        1: from (irb):11
NoMethodError (undefined method `active?' for #<Conversation:0x00007ff78097c910>)