
Rails provides a powerful feature called enum that allows you to map attribute values to integers in the database while keeping them human-readable in your application. This feature enables you to use symbols instead of raw integers in your code, making it more expressive and maintainable.
In this blog post, we’ll explore how to define and use enum attributes in Rails, covering everything from basic setup to advanced configurations like scopes, defaults, string persistence, and validations.
Basic Usage
To define an enum attribute, use the enum method in your model. Here’s a simple example:
class Order < ActiveRecord::Base
  enum :status, [ :pending, :shipped, :delivered, :cancelled ]
endHow It Works:
- The 
statuscolumn is stored as an integer in the database. :pendingis mapped to0,:shippedto1,:deliveredto2, and:cancelledto3based on their order.- You can update and query the attribute using either integers or symbols.
 
order = Order.new
order.status = :pending
order.pending? # => true
order.status  # => "pending"
order.status = 2
order.delivered? # => true
order.status    # => "delivered"Built-in Scopes
Using enums automatically creates scopes based on the attribute values:
Order.pending        # Fetches all pending orders
Order.not_pending    # Fetches all non-pending orders
Order.shipped        # Fetches all shipped orders
Order.delivered      # Fetches all delivered orders
Order.cancelled      # Fetches all cancelled ordersIf you want to disable these scopes, set :scopes to false:
class Order < ActiveRecord::Base
  enum :status, [ :pending, :shipped, :delivered, :cancelled ], scopes: false
endSetting Default Values
You can set a default value for an enum attribute using the :default option:
class Order < ActiveRecord::Base
  enum :status, [ :pending, :shipped, :delivered, :cancelled ], default: :pending
end
order = Order.new
order.status # => "pending"Explicit Mapping of Enum Values
If you prefer to define specific mappings instead of relying on implicit integer assignments, use a hash:
class Order < ActiveRecord::Base
  enum :status, pending: 0, shipped: 1, delivered: 2, cancelled: 3
endYou can also use string values instead of integers (though this may impact performance):
class Order < ActiveRecord::Base
  enum :status, pending: "pending", shipped: "shipped", delivered: "delivered", cancelled: "cancelled"
endAccessing Enum Mappings
To retrieve the integer value mapped to an enum symbol, use:
Order.statuses[:pending]    # => 0
Order.statuses["shipped"] # => 1This is useful when writing raw SQL queries:
Order.where("status <> ?", Order.statuses[:cancelled])Prefixes and Suffixes
When dealing with multiple enums that share similar values, you can use :prefix or :suffix to prevent conflicts:
class Order < ActiveRecord::Base
  enum :status, [ :pending, :shipped, :delivered, :cancelled ], suffix: true
  enum :payment_status, [ :pending, :completed, :failed ], prefix: :payment
endThis will generate:
order.pending_status!
order.shipped_status? # => false
order.payment_completed!
order.payment_pending? # => falseDisabling Instance Methods
If you don’t need the automatically generated methods, you can disable them:
class Order < ActiveRecord::Base
  enum :status, [ :pending, :shipped, :delivered, :cancelled ], instance_methods: false
endValidating Enum Values
To ensure only valid enum values are assigned, use :validate:
class Order < ActiveRecord::Base
  enum :status, [ :pending, :shipped, :delivered, :cancelled ], validate: true
endExample validation behavior:
order = Order.new
order.status = :unknown
order.valid? # => falseYou can also allow nil values:
class Order < ActiveRecord::Base
  enum :status, [ :pending, :shipped, :delivered, :cancelled ], validate: { allow_nil: true }
endHandling Errors
If an invalid value is assigned, an ArgumentError will be raised:
order.status = :unknown # Raises 'unknown' is not a valid status (ArgumentError)Conclusion
Using enum in Rails models simplifies your code, improves query readability, and enforces data integrity. Whether you’re defining simple status fields or complex multi-enum configurations, the flexibility of enum ensures that your models remain clean and maintainable.
By leveraging scopes, default values, explicit mappings, and validations, you can ensure that your application handles enumerations efficiently while maintaining a high level of clarity in your codebase.

