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.

Related Posts

Want to learn about the types of products we build?

Check out our projects

Like what you're seeing? Let's keep in touch.

Subscribe to Our Newsletter