2 November 2020
A simple trick to improve Rails performance and maintainability using enum
It is generally known that calls to the database are inherently slower than accessing a variable already in memory. You really do not want to create a bunch of small tables for simple values like status codes. In this discussion, we will look at enum to help us craft a better solution, and we’ll benefit from some syntactic sugar to sweeten things up for us developers as well.
In a recent project we needed to set and view the fulfillment status on orders. These needed to be human-readable so people on support calls could easily determine an order’s status. At first we just saved the actual status values as a string field, named fulfillment_status
, on our orders table. It did not take long to realize that we needed something better. We considered using a table but settled on using an enum instead. Our Order model now includes this enum:
enum fulfillment_status: {
new: 0,
picked: 1,
packed: 2,
shipped: 3,
error: 4
}, _prefix: true
The orders table now needed the fulfillment_status
field to be changed from a string to an integer. This requires a script in a migration which translates the existing status values into the integers of the enum. I will not cover that here, but if you are creating the table from scratch, you should have a migration that includes something like the following:
t.column :fulfillment_status, :integer, default: 0
add_index :orders, :fulfillment_status
Rails then wires up the enum and the model to work like one field. And to boot, we get syntactic sugar to make working with our new enum pattern even easier. Here are some examples.
What’s the current fulfillment_status?
order.fulfillment_status # returns a string from the enum, like 'new'
Is the fulfillment_status set to ‘new’?
order.fulfillment_status_new? # returns a boolean
This presents a wealth of developer friendliness in setting the value, as well. Pick the method you like best.
order.fulfillment_status = 'picked'
order.update(fulfillment_status: :packed)
order.fulfillment_status_shipped!
The enum is also easy to use as a dropdown in a form, as is shown in this example:
<%= select_tag :fulfillment_status, options_for_select(Order.fulfillment_statuses.map { |key,value| [key.capitalize, value] }, @order.fulfillment_status) %>
So in your next Rails project when you have a simple field with only a few possible choices, like a status field, I hope you will consider trying an enum. It will help performance by lightening database usage, and give you some syntactic sugar methods to make development easier.