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
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.