Enum(列挙型)とは
名前がついた定数の集まりです。
あらかじめ用意した選択肢の列挙からデータを選択することで、可読性の向上, 値の代入ミスを防ぐことができます。
DBのEnum(列挙型)
RailsのEnumを見る前にDBレベルでのENUMについて説明します。
DBのENUMはテーブル作成時に列挙された定義リストに存在する値のみを保管可能になるデータ型です。
要するに"banana", "apple", "orange"と定義すると、その3種類しか保存ができなくなります。
Ruby on RailsでのEnum
Railsのenum型は数値のカラム
に対してプログラム上で扱える別名を付与することで使用することが可能です。
重要な点としてDBレベルで見るとカラムの型は数値
です。
これにより、DBのカラムの型自体をEnumにした場合と比べ、カラムに保存可能な値を変更したい際に、DBの変更が必要になる点や、アプリ側からカラムに保存可能な値がわかりづらいという問題点を解消できます。
Enum型を定義する
今回はAnimalというModelを作成し、kindカラムに"猫", "犬", "それ以外"の選択肢を持つEnumを作成してみます
migration
先述の通りEnumとして管理するkindカラムはDBレベルでは数値型になります
rails g migration Animal name:string kind:integer
railg g db:migrate
model
Enumの定義はModelに記載します。
以下のように、文字列と数字を紐づけます。
class Animal < ApplicationRecord
enum kind: {
cat: 0, # 猫
dog: 1, # 犬
other: 2, # その他
}
略
end
irbで確認
これでEnumを扱うことができるようになります。
このような設定を行うことで、アプリ上では人間が理解しやすい文字列で扱い、DB上ではカラムの型である数字を保存できます。
Animal.create(name: "まる", kind: :cat)
=> <Animal id: 1, name: "まる", kind: "cat">
Animal.create(name: "ぽち", :kind: dog)
=> <Animal id: 2, name: "ぽち", kind: "dog">
使える便利メソッド/スコープ
animal = Animal.first
# インスタンスが特定の値なのか問い合わせ
animal.cat?
=> true
# !でインスタンスのEnum値を更新
animal.dog!
animal.dog?
=> true
# Enumの値を取得
animal.kind
=> "dog"
# 文字列ではなく、DBに保存された数値を取得
animal.kind_before_type_cast
=> 1
# Enumの選択肢を取得
Animal.kinds
=> {"cat"=>0,"dog"=>1,"other"=>2,}
# 未定義の値を保存しようとするとArgumentErrorが発生します
Animal.create(name: "gon", kind: :person)
=> ArgumentError ('person' is not a valid kinds)
# 全てのkind: catを取得
Animal.now_on_cat
# 全てのkind: cat以外を取得
Animal.not_now_on_cat