DEV Community

Junko T.
Junko T.

Posted on • Updated on

A comprehensive guide to Rails enum

Ruby on Rails logo

What is enum?

Enum is short for enumeration, a data type consisting of named elements, each having a different value. The enumerator names are usually identifiers that behave as constants in the language.

ActiveRecord::Enum was introduced in Rails 4.1. By declaring an enum attribute, you can map the values such as strings and symbols to integers in the database, and yet can query them by name. This means it has the speed and efficiency of an integer and the flexibility of a string or a symbol.


When can we use enum?

When the values of the field are constants. Let's say you create a Book model and it has a field of genre. You can map genre names to integers like: { fantasy: 0, adventure: 1, mystery: 2, romance: 3 }


How to implement enum?

Let's keep using the Book model example.

1.Add genre field to books as integer

class AddGenreToBooks < ActiveRecord::Migration[6.0]
  def change
    add_column :books, :genre, :integer
  end
end
Enter fullscreen mode Exit fullscreen mode

2.Add genre to the Book model

There are two ways to declare enum:

  • Using array
# app/models/book.rb
class Book < ActiveRecord::Base
  enum genre: [ :fantasy, :adventure, :mystery, :romance ]
end
Enter fullscreen mode Exit fullscreen mode

...or even simpler,

# app/models/book.rb
class Book < ActiveRecord::Base
  enum genre: %i(fantasy adventure mystery romance)
end
Enter fullscreen mode Exit fullscreen mode

For the syntax of %i() (percent strings), please refer to my blog post "Refactoring checklist for beautiful Ruby code"

  • Using hash
# app/models/book.rb
class Book < ActiveRecord::Base
  enum genre: { fantasy: 0, adventure: 1, mystery: 2, romance: 3 }
end
Enter fullscreen mode Exit fullscreen mode

Using hash is a good option if you want to assign specific numbers to the values.


Let's see how it works.

Query genre

# console
2.6.1 :001 > Book.genres # Check how the genre enum is defined
=> {"fantasy"=>0, "adventure"=>1, "mystery"=>2, "romance"=>3}
2.6.1 :002 > Book.genres[:adventure] # Check the identifier number of "adventure"
=> 1
2.6.1 :003 > Book.genres[:history] # If the genre doesn't exist, it returns nil
=> nil
Enter fullscreen mode Exit fullscreen mode

Create and update an instance

# console
2.6.1 :001 > book = Book.create(title: "The Lord of the Rings", genre: 0)
=> #<Book id: 1, title: "The Lord of the Rings", genre: "fantasy", created_at: "2020-12-03 03:27:05", updated_at: "2020-12-03 03:27:05">
2.6.1 :002 > book.genre # Check the genre
=> "fantasy"

# The following doesn't work when you use strings with spaces for enum.
2.6.1 :003 > book.adventure? # Check if the genre is "adventure"
=> false
2.6.1 :004 > book.adventure! # Update the genre
=> true
2.6.1 :005 > book.genre
=> "adventure"
Enter fullscreen mode Exit fullscreen mode

Enum in views

The cool thing about enum is you can treat it as symbols or strings in controllers and views and don't need to worry it is actually integers in the database.

# app/controllers/books_controller.rb
def index
  @books = Book.all
end

def new
  @book = Book.new
end
Enter fullscreen mode Exit fullscreen mode
# app/views/books/index.html.erb
<% @books.each do |book| %>
  <div><%= book.title %></div>
  <div><%= book.genre %></div>
<% end %>
Enter fullscreen mode Exit fullscreen mode
# app/views/books/new.html.erb
<%= form_for @book do |f| %>
  <%= f.select :genre, Book.genres.keys %>
  <%= f.submit %>
<% end %>
Enter fullscreen mode Exit fullscreen mode

ActiveRecord::Enum is a cheaper way to store data as it is an integer in memory, but yet allows you to use all the ActiveRecord methods you know.

Top comments (0)