こんにちは!oda@エンジニア1年目です!
業務では、今まで使っていなかったメソッドなど、様々なコードに触れる機会があります。
今回は、その中でもRuby on Railsのenumについて、整理してみたいと思います。
(以下、Rails 7.0.2.3を使用しています。)
はじめに
enumとは、属性で使う値を名前で参照できるようにする仕組みのことです。
これだけでは、非常にわかりにくいので、以下のコードを実行しながら、確認してみます。
事前準備
まずはFoodsテーブルを作成します。
bin/rails g model Foods name:string category:integer
models/food.rbを以下のように編集して、categoryにenumを設定します。
この時、以下のようにenumを配列で定義すると、:meatには0が、:vegetableには1が、:fruitには2が定義されます。
class Food < ApplicationRecord
enum :category, [
:meat,
:vegetable,
:fruit
]
end
次に、サンプルデータを作成します。
Food.create(name: "牛肉", category: :meat)
Food.create(name: "鶏肉", category: :meat)
Food.create(name: "トマト", category: :vegetable)
Food.create(name: "にんじん", category: :vegetable)
Food.create(name: "玉ねぎ", category: :vegetable)
Food.create(name: "りんご", category: :fruit)
Food.create(name: "みかん", category: :fruit)
Food.create(name: "バナナ", category: :fruit)
Food.create(name: "ぶどう", category: :fruit)
Food.create(name: "鯖")
enumの動作を確認
まずは、DBを確認してみます。categoryには、数値でデータが保存されています。
id | name | category
----+----------+----------
1 | 牛肉 | 0
2 | 鶏肉 | 0
3 | トマト | 1
4 | にんじん | 1
5 | 玉ねぎ | 1
6 | りんご | 2
7 | みかん | 2
8 | バナナ | 2
9 | ぶどう | 2
10 | 鯖 |
以下のように、categoryを呼び出してみると、定義した名前が返ってきます。
なお、鯖のようにcategoryが登録されていない場合は、nil
が返ってきます。
food1 = Food.find(1)
food1.name
food1.category
food10 = Food.find(10)
food10.name
food10.category
また、enumで定義した名前には、自動的にscopeが定義されるため、以下のように呼び出すことが可能です。
scopeとは、モデルに対して実行したいクエリを設定する仕組みです。
なお、notを付けて呼び出した場合、categoryがnilのものは呼び出されないので、注意が必要です。
foods_vegetable = Food.vegetable
foods_vegetable.all
[
foods_not_vegetable = Food.not_vegetable
foods_not_vegetable.all
[
さて、それではenumで設定されていないデータを登録しようとするとどうなるのでしょうか。
以下のとおり、エラーが発生し、登録はできません。
Food.create(name: '枝豆', category: :bean)
DBはそのままで、次のようにenumを追加するとどのようになるでしょうか。
class Food < ApplicationRecord
enum :category, [
:meat,
:fish,
:vegetable,
:fruit
]
end
試しに、トマトを見てみます。
tomato = Food.find(3)
トマトのcategoryがfishに変わってしまいました。
このように、配列の途中に追加すると、enumの採番が変わってしまうので、追加する場合は、最後にする必要があります。
なお、上記のenumは次のようにハッシュを使って、明示的に定義することもできます。
class Food < ApplicationRecord
enum :category, {
meat: 0,
vegetable: 1,
fruit: 2
}
end
ハッシュと使うと、次のように連番でない値を設定することもできます。
class Food < ApplicationRecord
enum :category, {
meat: 0,
vegetable: 1,
fruit: 2,
others: 9
}
end
今回は以上となります。
ご覧いただき、ありがとうございました!