Ruby
Rails
enum

便利なenum

はじめに
前回の記事でenumが出てきましたね。てな訳でenumです。僕もあんまり触ったとこないです。そんなenumの何が便利なのか調べていきましょう。

enumの活用例

enumとは簡単にいうと、 Railsのintegerクラスの属性の整数値にテキストでアクセスできる様にしてくれるものです。

schema.rb
ActiveRecord::Schema.define(version: 20181202084037) do

  create_table "users", force: :cascade do |t|
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
    t.string "name"
    t.string "email"
    t.string "user_id"
    t.integer "status"
    t.text "discription"
  end

end

上のUser.rbにてstatus属性で会員の状態を判断する場合。enumを使わない場合。数字で判断する羽目になり、可読性が悪いです。

member_status.rb
  if @user.status == 0
    #通常会員の処理
  elsif @user.status == 1
    #プレミアム会員の処理
  end

コメントがないとなんの処理をしているかわかりませんよね?

ではenumを使ってみましょう。
まずUser.rbにてstatus属性をenumとして定義します。

User.rb
class User < ApplicationRecord

  enum status: {
    normal:  0, #通常会員
    premium: 1, #プレミアム会員
  }

end

これでstatus属性にテキストのnormalpremiumでアクセスできます。

member_status.rb
  if @user.normal?
    #通常会員の処理
  elsif @user.premium? 
    #プレミアム会員の処理
  end

これなら、コードを見るだけでここでなんの処理が書かれているかわかりますよね!

enumで使えるメソッド

User.rb
class User < ApplicationRecord
  enum status: {
    normal:  0, #通常会員
    premium: 1, #プレミアム会員
  }
end

  user.premium!   # => userのstatusをpremiumでupdateする
  user.premium?   # => true
  user.status     # => "premium"

上記3つのメソッドは基本的によく使うであろうもの、下記のはある状況下で必要なもの。

User.rb
class User < ApplicationRecord
  enum course_status: {
    normal:  0, #通常会員コース
    premium: 1, #プレミアム会員コース
  }, _suffix: true

  enum age_group: {
    normal:  0,  #通常
    minority: 1, #未成年
  },  _prefix: :age_group
end

  user.normal_course_status!   # => userのcourse_statusをnormalでupdateする
  user.normal_course_status?   # => true

  user.age_group_normal!   # => userのage_groupをnormalでupdateする
  user.age_group_normal?   # => true

上の例ではcourse_statusage_groupnormalが被っています。その場合は_suffix:_prefixを用いて接頭辞・接尾辞を指定できるようにします。
_suffix:が接尾辞、_prefixが接頭辞です。

enumでの注意点

明示的に対応する整数値を指定しないと、識別子のリストの先頭から順に0,1,...と対応づけられていくので、以下の様に明示的に記載してない場合、例えばcatを削除する場合、kamoの対応する整数値が3から2になってしまいます。しかしDBに保存された値は3なので、対応する識別子がなくnillになってしまいます。

User.rb
class User < ApplicationRecord
  enum course_status: [pig:, dog:, cat:, kamo:]
end

上記から猫ちゃんを削除する時、その後、明示的に元の整数を指定してあげましょう。

User.rb
class User < ApplicationRecord
  enum course_status: {pig: 0, dog: 1, kamo: 3}
end

というより最初から明示的に書きましょう。

まとめ

いやあ便利、非常にコードが見やすくなります。是非使っていきましょう。
明日はscopeとやらについて掘り下げるンゴ

参考にしたの

ActiveRecord::Enum
https://api.rubyonrails.org/v5.2.1/classes/ActiveRecord/Enum.html

ActiveRecordのenumで気をつけたい3つのポイント
https://tech.misoca.jp/entry/2015/08/10/132419