💯

【Rails】enum型で複数の同じenum名を定義する

2022/04/07に公開

こんにちは。

標題の通り、enum型で複数の同じenum名を定義した際に発生するエラーを回避する方法を
学習したので、アウトプットしていきます。

尚、指摘箇所がございましたら
ご教授いただけますと幸いです。

前提

前提として、ジャンルテーブルを作成済みでカラムにenum型を定義しています。
*簡略化のため、一部省略しております。

genre.rb
class Genre < ApplicationRecord
  belongs_to :recipe
  validates :staple_food, :main_dish, presence: true

  enum staple_food: {
    others: 0,
    rice: 1,
    bread: 2,
    noodles: 3
  }
  enum main_dish: {
    others: 0,
    meat: 1,
    fish: 2,
    egg: 3,
    soybean: 4
  }
end

同じenum名を定義するとどうなるか?

enum staple_food: {
    others: 0,
    ...
    }
enum main_dish: {
    others: 0,
    ...
    }

では、上記のようにothersという名前が重複してしまうとどうなるのでしょうか。

Genre.create(recipe_id: 4, staple_food: 3, main_dish: 4)
~ `raise_conflict_error': You tried to define an enum named "staple_food" on the model "Genre", but this will generate a instance method "others?", which is already defined by another enum. (ArgumentError)

こうですね。
「"others?"というインスタンスメソッドを作りたいんだけど、もうすでに他のenum型によって定義されているよ」と怒られてしまいます。

回避方法

Railsではちゃんと同じ名前で定義ができるように整備されています。

You can use the :prefix or :suffix options when you need to define multiple enums with same values. If the passed value is true, the methods are prefixed/suffixed with the name of the enum. It is also possible to supply a custom value:
ActiveRecord::Enum

「同じ値で複数のenumを定義する必要があるときは:prefixもしくは:suffixを使えるよ」と教えてくれてます。
:prefixは接頭辞という意味で、例えば「ご相談」の「ご」がそれにあたります。
:suffixは接尾辞という意味で、例えば「彼ら」の「ら」がそれにあたります。

今回は:prefixで実装していきます。

genre.rb
class Genre < ApplicationRecord
  belongs_to :recipe
  validates :staple_food, :main_dish, presence: true

  enum staple_food: {
    others: 0,
    rice: 1,
    bread: 2,
    noodles: 3
+  }, _prefix: true
  enum main_dish: {
    others: 0,
    meat: 1,
    fish: 2,
    egg: 3,
    soybean: 4
+  }, _prefix: true
end

これで再度データを作成していきます。

Genre.create(recipe_id: 4, staple_food: 3, main_dish: 4)
  TRANSACTION (0.1ms)  BEGIN
  TRANSACTION (0.4ms)  SAVEPOINT active_record_1
  Recipe Load (1.0ms)  SELECT `recipes`.* FROM `recipes` WHERE `recipes`.`id` = 4 LIMIT 1
  Genre Create (0.8ms)  INSERT INTO `genres` (`recipe_id`, `staple_food`, `main_dish`, `created_at`, `updated_at`) VALUES (4, 3, 4, ***)
  TRANSACTION (0.1ms)  RELEASE SAVEPOINT active_record_1

こうですね。ちゃんとデータを作成することができました!
最後までお読みいただきありがとうございます!

Discussion