🚃

Rails 8ではenumで非推奨になっていた書き方が使用禁止になった話

2025/01/26に公開

はじめに

Rails 7.2 で enum のキーワード引数を使った定義が非推奨になり、Rails 8 ではそれが完全に禁止されました。本記事では、この変更の詳細と背景、移行の方法について解説します。

対象読者

  • Rails 開発者
  • 既存コードをメンテナンスしているエンジニア
  • Rails 8 へのアップデートを検討しているチーム

Rails 7.2以前の(非推奨の)書き方

class Conversation < ApplicationRecord
  enum status: { active: 0, archived: 1 }, _prefix: true
end

Rails 7.2 では、上記のような「キーワード引数を使用した列挙型の定義」が非推奨になりました。

こちらのテックブログにて、enumのコード解説をされてました。
https://media.zenet-web.co.jp/entry/2024/07/01/085407
enumコードの確認

def enum(name = nil, values = nil, **options)
  if name
    values, options = options, {} unless values
    return _enum(name, values, **options)
  end

  definitions = options.slice!(:_prefix, :_suffix, :_scopes, :_default, :_instance_methods)
  options.transform_keys! { |key| :"#{key[1..-1]}" }

  definitions.each { |name, values| _enum(name, values, **options) }

  ActiveRecord.deprecator.warn(<<~MSG)
    Defining enums with keyword arguments is deprecated and will be removed
    in Rails 7.3. Positional arguments should be used instead:

    #{definitions.map { |name, values| "enum :#{name}, #{values}" }.join("\n")}
  MSG
end

第一引数が位置引数かキーワード引数かで処理が分かれていたのですね。

コードを見るに、7.3でも完全廃止になる可能性が高そうですね。

Rails 8での変更: キーワード引数の完全廃止

Rails 8 では、非推奨だったキーワード引数を使う定義が 完全に禁止 され、エラーとなります。

kamal-rails(dev)> user = User.new
app/models/user.rb:2:in '<class:User>': wrong number of arguments (given 0, expected 1..2) (ArgumentError)
        from app/models/user.rb:1:in '<main>'
        from (kamal-rails):29:in '<main>'

推奨される書き方

非推奨の書き方に代わり、以下の形式に変更しましょう

class Conversation < ApplicationRecord
  enum :status, { active: 0, archived: 1 }, prefix: true
end

今後は「第一引数に位置引数を設定する」で揃えましょう!!

公式を確認する

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

integerカラムでenumを使用する場合は下記のように書くことができます。

class Conversation < ApplicationRecord
  enum :status, [ :active, :archived ]
end

便利ですね。

もちろん、ハッシュを使って、属性とデータベースの整数の関係を明示的にマッピングすることもできます。

class Conversation < ApplicationRecord
  enum :status, active: 0, archived: 1
end

ちなみにstringカラムとしenumを使用する場合は下記のように書くことができます。

class Conversation < ApplicationRecord
  enum :status, active: "active", archived: "archived" 
end

公式でも言われていますが、「データベースのクエリが遅くなる可能性が高いことに注意してください」とのこと。

Discussion