Introduction
Enums let you define a set of named values for an attribute, backed by integers in the database. Instead of storing strings and worrying about typos, enums give you type-safe constants, query scopes, and predicate methods — all generated automatically.
Key Concepts
enum: A class method mapping named values to integers, providing scopes, predicates, and bang methods.- Integer-backed: Enum values are stored as integers for efficient storage and indexing.
- Hash syntax: Rails 7+ requires
enum :status, { draft: 0, published: 1 }.
Real World Context
Almost every model has a status-like attribute: order status, article state, user role. Enums are the standard Rails approach. They replace magic strings with a clean API.
Deep Dive
Defining Enums
Rails 7+ uses hash syntax with keyword arguments:
rubyclass Article < ApplicationRecord enum :status, { draft: 0, published: 1, archived: 2 } enum :category, { tech: 0, science: 1, business: 2 }, prefix: true end
The integers are stored in the database. Always use explicit mappings.
Generated Methods
rubyarticle = Article.new(status: :draft) article.draft? # => true article.published? # => false article.published! # Sets to published and saves Article.draft # Scope: all draft articles Article.published # Scope: all published articles Article.statuses # => {"draft"=>0, "published"=>1, "archived"=>2}
With prefix: true, methods become: article.category_tech?.
Migration
rubyclass AddStatusToArticles < ActiveRecord::Migration[8.1] def change add_column :articles, :status, :integer, default: 0, null: false add_index :articles, :status end end
The default: 0 corresponds to :draft. Always add an index.
Prefix and Suffix Options
rubyclass User < ApplicationRecord enum :role, { admin: 0, moderator: 1, member: 2 }, prefix: :role enum :status, { active: 0, archived: 1 }, suffix: :status end user.role_admin? # => true user.active_status? # => true
Prefixes and suffixes prevent method name collisions.
Validation
rubyclass Article < ApplicationRecord enum :status, { draft: 0, published: 1, archived: 2 }, validate: true end article = Article.new(status: :invalid) article.valid? # => false (instead of raising ArgumentError)
Common Pitfalls
- Using array syntax:
enum status: [:draft, :published]is deprecated in Rails 7+. Use hash syntax. - Adding values in the middle: New values must go at the end with the next integer. Inserting in the middle shifts existing records' meanings.
- No database default: Without a default, new records have NULL status.
Best Practices
- Always use explicit integer mappings (hash syntax).
- Add new enum values at the end, never in the middle.
- Use
prefix: truewhen enum names might clash. - Add an index on enum columns.
Summary
- Enums map named values to integers, providing predicates, bang methods, and scopes.
- Rails 7+ requires hash syntax:
enum :status, { draft: 0, published: 1 }. - Use
prefix:orsuffix:to avoid method name collisions. - Always add new values at the end with the next integer.
- Add a database default and index on enum columns.
Code Examples
ruby
class Article < ApplicationRecord
enum :status, { draft: 0, published: 1, archived: 2 }
end
article = Article.new(status: :draft)
article.draft? # => true
article.published! # Updates to published and saves
Article.published # Scope: all published articles
Article.statuses # => {"draft"=>0, "published"=>1, "archived"=>2}