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
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
...or even simpler,
# app/models/book.rb
class Book < ActiveRecord::Base
enum genre: %i(fantasy adventure mystery romance)
end
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
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
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"
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
# app/views/books/index.html.erb
<% @books.each do |book| %>
<div><%= book.title %></div>
<div><%= book.genre %></div>
<% end %>
# app/views/books/new.html.erb
<%= form_for @book do |f| %>
<%= f.select :genre, Book.genres.keys %>
<%= f.submit %>
<% end %>
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)