Improving Rails Enums using i18n

Posted on

As of Rails 4.1, you can use Enums to sensibly store a set of fixed constants against a field. These are handy as upon declaring your enum attributes, Rails will define a bunch of methods and scopes that follow Ruby’s naming conventions.

One of the areas I felt they didn’t totally satisfy my needs, was when it came to displaying the enum fields value to the end user in a view.

Enum I18n Helper

The solution I decided was most “the rails way” was to store a translated version of the enum key in the locale YAML file, then use a helper to retrieve the translated value. Below is the helper.

# app/helpers/enum_i18n_helper.rb
module EnumI18nHelper

  # Returns an array of the possible key/i18n values for the enum
  # Example usage:
  # enum_options_for_select(User, :approval_state)
  def enum_options_for_select(class_name, enum)
    class_name.send(enum.to_s.pluralize).map do |key, _|
      [enum_i18n(class_name, enum, key), key]

  # Returns the i18n version the models current enum key
  # Example usage:
  # enum_l(user, :approval_state)
  def enum_l(model, enum)
    enum_i18n(model.class, enum, model.send(enum))
  # Returns the i18n string for the enum key
  # Example usage:
  # enum_i18n(User, :approval_state, :unprocessed)
  def enum_i18n(class_name, enum, key)


For this example, I’m going to create the enum approval_state in my User model, like so:

# app/model/user.rb
class User < ActiveRecord::Base
  enum approval_state: { unprocessed: 0, approved: 1, declined: 2 }

The YAML file should then contain a list of the translated keys under the pluralised version of the enum attribute:

# config/locales/activerecord.en.yml
          unprocessed: "Unprocessed"
          approved: "Approved"
          declined: "Declined"

You can then output a users current approval_state by doing the following:

<%= enum_l(user, :approval_state) %>

You can also have a list of all the available options for that enum in a select box, like so:

 <div class="form-group">
   <%= f.label :approval_state %>
   <%= :approval_state, enum_options_for_select(User, :approval_state) %>

Update 2019: I found a better solution

After writing this, I found this StackOverflow post with a better solution. I think it’s a much better compared to the one posted above.