Rails 7.1 introduces a new option to exclude all custom methods generated by the ActiveRecord::Enum

railsDecember 12, 2023Dotby Alkesh Ghorpade

ActiveRecord::Enum is a feature introduced in Rails 4.1 that allows you to define attributes with a limited set of allowed values. These values are stored as integers in the database but can be accessed and manipulated by name within your Rails application.

To know more about Enum functionality, please refer to our previous blog post.

Before Rails 7.1

Defining an enum in ActiveRecord automatically generates several methods for querying, manipulating, and accessing the enum values of a model instance.

Here's an example of how to define and use an enum for an Order status attribute:

class Order < ApplicationRecord
  enum status: { pending: 0, shipped: 1, completed: 2 }
end

# Access enum values
Order.statuses
=> { pending: 0, shipped: 1, completed: 2 }

order = Order.first
order.status
=> 'pending'

# Access integer equivalents
Order.statuses[:pending] 
=> 0

order.status_value
=> 0

# Querying based on enum values
Order.shipped

SELECT "orders".* FROM "orders" WHERE "orders"."status" = $1 /* loading for pp */ LIMIT $2  [["status", 1], ["LIMIT", 11]]

# verify order values
order = Order.first
order.pending?
=> true

order.shipped?
=> false

# update order status
order.shipped!

Before Rails 7.1, if you want to turn off enums, there are workarounds and alternatives you can use:

1. Override generated methods:

You can manually override the generated methods in your model class. This approach requires more coding but gives you fine-grained control over the implementation.

class Order < ApplicationRecord
  enum status: { pending: 0, shipped: 1, completed: 2 }

  def pending?
    status == :pending
  end

  def shipped!
    update!(status: :shipped)
  end
end

2. Use scopes instead of methods:

If you mainly use the generated methods for querying, consider using scopes instead. Scopes are more concise and efficient for filtering based on enum values.

class Order < ApplicationRecord
  enum status: { pending: 0, shipped: 1, completed: 2 }

  scope :pending, -> { where(status: :pending) }
  scope :shipped, -> { where(status: :shipped) }
end

3. Use a Rails plugin:

Several plugins like enum_without_methods and rails_enum_without_methods provide an easier way to turn off enum method generation.

4. Use a custom enum implementation:

If you need advanced control over enum functionality, consider implementing your own enum solution without relying on the ActiveRecord methods.

Before Rails 7.1, when disabling methods, you had to be aware of potential side effects and ensure your code handles the enum values correctly.

In Rails 7.1

Rails 7.1 option to disable all methods that ActiveRecord.enum generates. You need to pass instance_methods: false when declaring the enum in the model.

class Order < ApplicationRecord
  enum status: { pending: 0, shipped: 1, completed: 2 }, instance_methods: false
end

order = Order.first
order.pending?
=> `method_missing': undefined method `pending?' for #<Order id: "8de...

This feature is beneficial where the methods generated by the enum are conflicting, and most of the time, not all methods are required.

How disabling ActiveRecord Enums is helpful

Improves performance: By disabling the generation of dynamic methods, you can improve the performance of your application.

Reduces code size: Disabling enums can reduce the size of your application code, which can be beneficial in resource-constrained environments.

Provides more control: Disabling enums gives you more control over how you handle the enum values in your application.

Easier integration with external systems: By storing the enum values as integers, you can avoid any potential issues with data conversion when integrating with external systems.

To know more about this feature, please refer to this PR.

Closing Remark

Could your team use some help with topics like this and others covered by ShakaCode's blog and open source? We specialize in optimizing Rails applications, especially those with advanced JavaScript frontends, like React. We can also help you optimize your CI processes with lower costs and faster, more reliable tests. Scraping web data and lowering infrastructure costs are two other areas of specialization. Feel free to reach out to ShakaCode's CEO, Justin Gordon, at justin@shakacode.com or schedule an appointment to discuss how ShakaCode can help your project!
Are you looking for a software development partner who can
develop modern, high-performance web apps and sites?
See what we've doneArrow right