For Rails developers, using enums with ActiveRecord is always a good choice when you have to manage the state of an object. For example, for an online shop, you may have three states of an order - i.e. received
, dispatched
and delivered
. One option is to add three boolean fields in the database for received
, dispatched
and delivered
, but this approach looks ugly. A cleaner approach is to add a single string column status that includes values of received
, dispatched
and delivered
, then add three methods in the model file.
1
2
3
4
5
6
7
8
9
10
11
12
13
class Order < ApplicationRecord
def received?
status == "received"
end
def dispatched?
status == "dispatched"
end
def delivered?
status == "delivered"
end
end
Though this is a better approach than using boolean fields, it’s still not the most efficient due to the fact that values are stored as integers in the database and can be queried by name.
With enums, you have to create an integer field in the database named status.
1
rails generate migration add_status_to_orders status:integer
Make sure your newly created migration file looks like this:
1
2
3
4
5
class AddStatusToOrders < ActiveRecord::Migration[6.0]
def change
add_column :orders, :status, :integer, default: 0
end
end
Run rails db:migrate
.
In app/models/order.rb
, declare your enum.
1
2
3
class Order < ApplicationRecord
enum status: { received: 0, dispatched: 1, delivered: 2 }
end
Test your implementation.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
order = Order.create
order.received?
=> true
order.status
=> "received"
order.dispatched!
(0.2ms) BEGIN
Order Update (0.6ms) UPDATE "orders" SET "updated_at" = $1, "status" = $2 WHERE "orders"."id" = $3 [["updated_at", "2020-05-23 12:17:35.782738"], ["status", 1], ["id", 1]]
(1.3ms) COMMIT
=> true
order.dispatched?
=> true
order.status
=> "dispatched"
That’s it - happy managing!