はじめに
Railsに触れ始め1ヶ月あまり、ふとenum
に出会った。
その出会いについてまとめてみます
出会い
Aさん: 権限とか状態がこのサービスにはたくさんあるんだ
自分: へーそうなんですね。(覚えるの大変そうだな。。。)
しばらく一人で調べてみる。それっぽいのはあるけど、なんかよくわからん。なので聞いてみた
自分: 権限とかってどうやって判断してるんですか?
Aさん: enum 使ってる
自分: enum?何それおいしいの?
私は〜こうして〜enumと~出会ったので〜あったー。
enum is nani?
- 皆大好き
ActiveRecord
の追加されたモジュールです。(4.1以降) - 特定のカラムの値と文字列(シンボル)をマッピングさせる
何が嬉しいの?
Userモデルにstate
カラムがあり、属性としてactive
とinactive
があると仮定します。おそらく下記のどちらかのパターンで設計する可能性があるかと思います。
カラム名 | 型 | 値 | 作成方法 |
---|---|---|---|
state | string | active or inactive | rails g model User state:string |
state | integer | 1 or 2 | rails g model User state:integer |
この時に、「とあるユーザがactive
かどうか?」をどう実現しますか?
user.state == 'active'
user.state == 1
テーブルや属性値が少なければこれで全然問題ないと思います。ただこれが増えていくと大変です。そこで enum の出番です。
enumでやってみる
まずはUserモデルを作成します。enumで操作するカラムの型はinteger
にします。
あとはmigrateしてあげましょう。
rails g model User state:integer
rails db:migrate
次に、enumでやるためにUserモデルにカラムに対するマッピングを定義します。
class User < ApplicationRecord
enum status: { active: 1, inactive: 2 }
end
これで準備は整いました。active
なユーザを作ってみましょう。
❯ rails c
Running via Spring preloader in process 8159
Loading development environment (Rails 5.1.7)
User.create(name: 'A', state: :active)
(0.1ms) begin transaction
SQL (0.4ms) INSERT INTO "users" ("name", "state", "created_at", "updated_at") VALUES (?, ?, ?, ?) [["name", "A"], ["state", 1], ["created_at", "2020-04-25 12:42:27.161288"], ["updated_at", "2020-04-25 12:42:27.161288"]]
(1.0ms) commit transaction
=> #<User id: 1, name: "A", state: "active", created_at: "2020-04-25 12:42:27", updated_at: "2020-04-25 12:42:27">
ユーザが作成されましたね。integerで型定義したはずのstate
にactiveと入っていますね。
さてこのユーザがactive
なユーザかどうかをチェックしてみましょう。
User.first.active?
User Load (0.3ms) SELECT "users".* FROM "users" ORDER BY "users"."id" ASC LIMIT ? [["LIMIT", 1]]
=> true
逆にinactive
かどうかをチェックしてみましょう。
User.first.inactive?
User Load (0.2ms) SELECT "users".* FROM "users" ORDER BY "users"."id" ASC LIMIT ? [["LIMIT", 1]]
=> false
次にactive
なuser一覧を取得してみましょう。
User.where(state: :active)
User Load (0.3ms) SELECT "users".* FROM "users" WHERE "users"."state" = ? LIMIT ? [["state", 1], ["LIMIT", 11]]
=> #<ActiveRecord::Relation [#<User id: 1, name: "A", state: "active", created_at: "2020-04-25 12:42:27", updated_at: "2020-04-25 12:42:27">]>
上記のクエリを見ると、データベース上ではちゃんと値(integer)で保存されているのが確認できますね。enumを使うと、コードをより直感的かつわかりやすくすることができるようになります。
また定義した enum を複数形にしてあげることで定義済みのマッピングを取得することができます。
User.states
=> {"active"=>1, "inactive"=>2}
まとめ
enumを使うことでDBに保存されている値を気にする必要があまりなくなり、かつ直感的にすることができます。ぜひ活用していきたいなと思います。
素晴らしいものに出会えた。。。。。