0.0
No commit activity in last 3 years
No release in over 3 years
Create enums for Rails model attributes like enums in C languages
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
 Dependencies

Development

Runtime

>= 3.2.0
 Project Readme

RailsAttrEnum

Enums for Rails attributes. Specify enumeration identifiers for int attributes on your Rails models. Includes constants for your identifiers, validation, model class scopes, and instance helper methods.

Build Status

Build Status

Installation

Add to your Gemfile:

gem 'rails_attr_enum'

And then run bundler:

$ bundle install

Usage

Here's an example given a class User with an attribute role:

# Example model User for a blog app
class User < ActiveRecord::Base
  extend RailsAttrEnum
  attr_enum :role, :admin, :editor, :author, :user
end

# Creates module `User::Role` with constants for each possible value
User::Role::ADMIN  == 0
User::Role::EDITOR == 1
User::Role::AUTHOR == 2
User::Role::USER   == 3

View other ways to define and customize enums

Helpers for Model Instances

A couple helpers methods are added to the model and the enum attribute.

Get the "display" label for the current value with the display_* method:

user = User.new(role: User::Role::ADMIN)
user.display_role == 'Admin'

You can check for a specific value with a query *? method:

user = User.new(role: User::Role::AUTHOR)
user.role.admin?  # false
user.role.editor? # false
user.role.author? # true
user.role.user?   # false

The query method works via a forwarding class, so the normal role and role= methods should work as expected.

NOTE: one caveat to this is if you try to use a hash map of the enum values to some other value. See below:

alt_label_map = {
  User::Role::ADMIN  => 'The admin user',
  User::Role::EDITOR => 'An editor',
  User::Role::AUTHOR => 'An author',
  User::Role::USER   => 'A user'
}

user = User.new(role: User::Role::EDITOR)
alt_label = alt_label_map[user.role]
alt_label == nil # not 'An editor'

If you want the hash to work as expected then call the .value method on the attribute:

alt_label = alt_label_map[user.role.value]
alt_label == 'An editor'

Thus, the .value method on the attribute gives the actual Fixnum value. There is also a .key method which gives the symbol key:

user = User.new(role: User::Role::ADMIN)
user.role.key == :admin

The attribute value can also be set with a bang *! method

user = User.new
user.role.user!
user.display_role == 'User'

user.role.author!
user.display_role == 'Author'

Scopes for Models

Convenient scopes are created for each possible enum value on the model class:

User.role_admin  == User.where(role: User::Role::ADMIN)
User.role_editor == User.where(role: User::Role::EDITOR)
User.role_author == User.where(role: User::Role::AUTHOR)
User.role_user   == User.where(role: User::Role::USER)

Enum Helper Methods

Helper methods are added to the actual Enum module as well.

get_label and get_key

Get the (surprise!) label and key for a given enum value:

User::Role.get_label(User::Role::ADMIN) == 'Admin'
User::Role.get_key(User::Role::USER) == :user

attr_name

Return the attribute name as a symbol

User::Role.attr_name == :role

keys

Return all the enum keys

User::Role.keys == [:admin, :editor, :author, :user]

values

Return all the enum values

User::Role.values == [0, 1, 2, 3]

labels

Return all the enum labels

User::Role.labels == ['Admin', 'Editor', 'Author', 'User']

label_value_pairs

Return an array of pairs of the label and value for each enum value. This is mainly a convenience method for something like the collection option for a select input in the Formtastic or ActiveAdmin (which uses Formtastic) gems, so you can easily generate select options:

User::Role.label_value_pairs == [
  ['Admin', 0], ['Editor', 1], ['Author', 2], ['User', 3]
]

# In an ActiveAdmin form
ActiveAdmin.register User do
  form do |f|
    f.inputs 'User Details' do
      f.input :first_name
      f.input :last_name
      f.input :email

      # Example usage of `label_value_pairs`
      f.input :role, as: :select, collection: User::Role.label_value_pairs
    end
  end
end

You can also filter the results by passing in enum value keys as symbol arguments:

User::Role.label_value_pairs(:admin, :author) == [
  ['Admin', 0], ['Author', 2]
]

to_h and to_json

to_h and to_json return a hash and a json string representation of the enum, respectively. They both offer an only and an except option to specify if you only want the value or maybe only the label and key or if you want everything but key. NOTE: passing only key to only or excluding all but one key via except will give that single value (whether it's value, key, or label) instead of a hash. See below to understand:

# Default call with no options
User::Role.to_h == {
  'ADMIN'  => { key: :admin,  label: 'Admin',  value: 0 },
  'EDITOR' => { key: :editor, label: 'Editor', value: 1 },
  'AUTHOR' => { key: :author, label: 'Author', value: 2 },
  'USER'   => { key: :user,   label: 'User',   value: 3 }
}

# Call with a single symbol (would also work with `only: [:value]`)
# Notice the mapped values are not hashes like above because we only
# specified that we wanted the value
User::Role.to_h(only: :value) == {
  'ADMIN'  => 0,
  'EDITOR' => 1,
  'AUTHOR' => 2,
  'USER'   => 3
}

# Would also work with `except: [:value]`
User::Role.to_json(except: :value) ==
  "{\"ADMIN\":{\"key\":\"admin\",\"label\":\"Admin\"},\"EDITOR\":{\"key\":\"editor\",\"label\":\"Editor\"},\"AUTHOR\":{\"key\":\"author\",\"label\":\"Author\"},\"USER\":{\"key\":\"user\",\"label\":\"User\"}}"

Feedback and Pull Requests Welcome

This is my first real Rails gem, so I welcome all feedback and ideas. I hope this gem is as helpful to you as it has been to me in my own projects.