Created: 2011-07-07 09:48
Updated: 2018-12-07 03:45



Gem Version Maintainability Test Coverage Build Status

Rails plugin for Enumerations in ActiveRecord models.


Inside your Gemfile add the following:

gem 'enumerations'


Defining enumerations

Create a model for your enumerations:

class Status < Enumerations::Base
  values draft:           { name: 'Draft' },
         review_pending:  { name: 'Review pending' },
         published:       { name: 'Published' }

Or you can use value method for defining your enumerations:

class Status < Enumerations::Base
  value :draft,           name: 'Draft'
  value :review_pending,  name: 'Review pending'
  value :published,       name: 'Published'

Include enumerations for integer fields in other models:

class Post < ActiveRecord::Base
  enumeration :status

  validates :status, presence: true

You can pass attributes to specify which enumeration and which column to use:

class Post < ActiveRecord::Base
  enumeration :status,
              foreign_key: :post_status,   # specifies which column to use
              class_name: Post::Status     # specifies the class of the enumerator

  validates :post_status, presence: true

Attribute foreign_key you can pass as a String or a Symbol. Attribute class_name can be set as a String, a Symbol or a String.

Setting enumeration value to objects

Set enumerations:

@post = Post.first
@post.status = Status.draft

Or you can set enumerations by symbol:

@post.status = Status.find(:draft)

If you try to set value that is not an Enumeration value (except nil), you will get an Enumerations::InvalidValueError exception.

Also, you can set enumeration value like this:


When you include enumerations into your model, you'll get methods for setting each enumeration value. Each method name is consists from enumeration name and enumeration value name with ! at the end. Examples:

class Post < ActiveRecord::Base
  enumeration :status

class User < ActiveRecord::Base
  enumeration :role

class User < ActiveRecord::Base
  enumeration :type, class_name: Role


Finder methods

Find enumerations by id:

@post.status = Status.find(2)                 # => Review pending

Other finding methods:

# Find by key as a Symbol
Status.find(:review_pending)                  # => Review pending

# Find by key as a String
Status.find('draft')                          # => Draft

# Find by multiple attributes
Status.find_by(name: 'None', visible: true)   # => None

Compare enumerations:

@post.status == :published                    # => true
@post.status == 'published'                   # => true
@post.status == Status.published              # => true
@post.status.published?                       # => true

Get all enumerations:


Filtering methods

Enumerations can be filtered with where method, similar to ActiveRecord::QueryMethods#where.

Role.where(admin: true)                       # => [Role.admin, Role.editor]
Role.where(admin: true, active: true)         # => [Role.admin]

Scopes on model

With enumerations, you'll get scope for each enumeration value in the following format:


or you can use the following scope and pass an array of enumerations:

with_#{enumeration_name}(enumeration, ...)
without_#{enumeration_name}(enumeration, ...)


class Post < ActiveRecord::Base
  enumeration :status

Post.with_status_draft                        # => <#ActiveRecord::Relation []>
Post.without_status_review_pending            # => <#ActiveRecord::Relation []>
Post.with_status(:draft)                      # => <#ActiveRecord::Relation []>
Post.without_status(:draft)                   # => <#ActiveRecord::Relation []>
Post.with_status(Status.draft)                # => <#ActiveRecord::Relation []>
Post.with_status(:draft, :review_pending)     # => <#ActiveRecord::Relation []>
Post.with_status(Status.draft, 'published')   # => <#ActiveRecord::Relation []>
Post.with_status([:draft, :review_pending])   # => <#ActiveRecord::Relation []>
class Post < ActiveRecord::Base
  enumeration :my_status, class_name: Status

Post.with_my_status_draft                      # => <#ActiveRecord::Relation []>
Post.with_my_status_review_pending             # => <#ActiveRecord::Relation []>
Post.with_my_status(:draft)                    # => <#ActiveRecord::Relation []>
Post.without_my_status(:draft)                 # => <#ActiveRecord::Relation []>

Each scope returns all records with specified enumeration value.

Forms usage

Use in forms:

  = f.label :status
  = f.collection_select :status, Status.all, :symbol, :name

Advanced Usage

Except name you can specify any other attributes to your enumerations:

class Status < Enumerations::Base
  value :draft,           id: 1, name: 'Draft', published: false
  value :review_pending,  id: 2, name: 'Review pending', description: 'Some description...'
  value :published,       id: 3, name: 'Published', published: true
  value :other                                 # passing no attributes is also allowed

Every enumeration has id, name, description and published methods. If you call method that is not in attribute list for enumeration, it will return nil.

Status.review_pending.description              # => 'Some description...'
Status.draft.description                       # => nil

For each attribute, you have predicate method. Predicate methods are actually calling present? method on attribute value:

Status.draft.name?                             # => true
Status.draft.published?                        # => false
Status.published.published?                    # => true
Status.other.name?                             # => false


Enumerations uses power of I18n API to enable you to create a locale file for enumerations like this:

        name: Draft
        description: Article draft...
        name: Administrator

You can separate enumerations locales into a separate *.yml files. Then you should add locale file paths to I18n load path:

# config/initializers/locale.rb

# Where the I18n library should search for translation files (e.g.):
I18n.load_path += Dir[Rails.root.join('config', 'locales', 'enumerations', '*.yml')]


Basically no configuration is needed.

Enumerations has two configuration options. You can customize primary key and foreign key suffix. Just add initializer file to config/initializers/enumerations.rb.

Example of configuration:

# config/initializers/enumerations.rb

Enumerations.configure do |config|
  config.primary_key        = :id
  config.foreign_key_suffix = :id

By default, primary_key and foreign_key_suffix are set to nil.

By default model enumeration value is saved to column with same name as enumeration. If you set enumeration as:

enumeration :status

then model should have status column (as String type). If you want save an ID to this column, you can set foreign_key_suffix to id. Then model should have status_id column.

If you set primary_key then you need provide this attribute for all enumerations values. Also, value from primary_key attribute will be stored to model as enumeration value.

For example:

# with default configuration

post = Post.new
post.status = Status.draft      # => post.status = 'draft'

# with configured primary_key and foreign_key_suffix:

Enumerations.configure do |config|
  config.primary_key        = :id
  config.foreign_key_suffix = :id

class Status < Enumerations::Base
  value :draft,           id: 1, name: 'Draft'
  value :review_pending,  id: 2, name: 'Review pending',
  value :published,       id: 3, name: 'Published', published: true

post = Post.new
post.status = Status.draft      # => post.status_id = 1

If you want to configure primary key per enumeration class, you can use primary_key= class method:

class Status < Enumerations::Base
  self.primary_key = :id

  value :draft,           id: 1, name: 'Draft'
  value :review_pending,  id: 2, name: 'Review pending'

Database Enumerations

By default, enumeration values are saved to database as String. If you want, you can define Enum type in database:

CREATE TYPE status AS ENUM ('draft', 'review_pending', 'published');

Then you'll have enumeration as type in database and you can use it in database migrations:

add_column :posts, :status, :status, index: true

With configuration option primary_key, you can store any type you want (e.g. Integer).

Also, for performance reasons, you should add indices to enumeration column.

Here you can find more informations about ENUM types.


  1. Fork it
  2. Create your feature branch (git checkout -b my-new-feature)
  3. Commit your changes (git commit -am 'Add some feature')
  4. Push to the branch (git push origin my-new-feature)
  5. Create new Pull Request


Enumerations is maintained and sponsored by Infinum

Copyright © 2010 - 2018 Infinum Ltd.


The gem is available as open source under the terms of the MIT License.

Cookies help us deliver our services. By using our services, you agree to our use of cookies Learn more