Skip to content

Repository files navigation

Define enum classes in Rails and use them to enumerate ActiveRecord attributes. Brings together some ideas of similar plugins that I liked and does it they way I prefer.

Enum values are stored in memory at the moment but I plan to add database and possibly others. See Storage Backends.

From version 0.7 onwards this plugin will only have Rails 3 support. If you need Rails 2 compatibility, check the 0.6 branch.

geminstallactive_enum

Put this in your Gemfile

gem'active_enum'

Then generate the config initializer file

railsgenerateactive_enum:install

Define an enum class with values

classSex<ActiveEnum::Basevalue:id=>1, :name=>'Male'value:id=>2, :name=>'Female'end

Define with id as the key

classSex<ActiveEnum::Basevalue1=>'Male'value2=>'Female'end

Define using implicit id values

classSex<ActiveEnum::Basevalue:name=>'Male'value:name=>'Female'end

Beware that if you change the order of values defined in an enum which don’t have explicit ids, then the ids will change. This could corrupt your data if the enum values have been stored in a model record, as they will no longer map to the original enum.

Define values with meta data

classSex<ActiveEnum::Basevalue:id=>1, :name=>'Male', :symbol=>'♂'value:id=>2, :name=>'Female', :symbol=>'♀'end

The meta data can be any other key-value pairs, it’s not limited to certain keys.

Enum class usage

Sex[1] # => 'Male'Sex['Male'] # => 1Sex[:male] # => 1Sex.meta(1) # => { :symbol => '♂' }Sex.to_select# => [['Male', 1], ['Female',2]] for select form helpers

To define the sorting of returned values use the order method. Which is useful for to_select method.

classSex<ActiveEnum::Baseorder:ascvalue:id=>1, :name=>'Male'value:id=>2, :name=>'Female'end

By default the order is ascending (:asc) but you can also choose descending (:desc) or in natural order of definition (:natural). The last option is useful when supplying id values but have a specific order needed to display them.

Use the enum to enumerate an ActiveRecord model attribute

classUser<ActiveRecord::Baseenumerate:sex, :with=>Sexend

Skip the with option if the enum can be implied from the attribute

classUser<ActiveRecord::Baseenumerate:sexend

Define enum class implicitly from enumerate block. Enum class is namespaced by model class.

classUser<ActiveRecord::Base# defines User::Sex enum classenumerate:sexdovalue:name=>'Male'endend

Multiple attributes with same enum

classPatient<ActiveRecord::Baseenumerate:to, :from, :with=>Sexend

You can use an enum in a validation of inclusion like so

classUser<ActiveRecord::Baseenumerate:sex, :with=>Sexvalidates_inclusion_of:sex, :in=>Sexend

This works because an enum class responds to #include?().

Access the enum values and the enum class using the attribute method with a symbol for the enum component you want

user = User.newuser.sex = 1user.sex# => 1user.sex(:id) # => 1user.sex(:name) # => 'Male'user.sex(:enum) # => Sexuser.sex(:symbol) # => ♂ ( Can use any meta data key )

You can set the default to return the enum name value for enumerated attribute

ActiveEnum.use_name_as_value = trueuser.sex# => 'Male'

You can check if the attribute value matches a particular enum value by passing the enum value as an argument to the question method

user.sex?(:male) # => trueuser.sex?(:Male) # => trueuser.sex?('Male') # => trueuser.sex?('Female') # => false

A convenience method on the class is available to the enum class of any enumerated attribute

User.active_enum_for(:sex) # => Sex

Define enum classes in bulk without class files, in an initializer file for example.

ActiveEnum.definedo# defines Sexenum(:sex) dovalue:name=>'Male'value:name=>'Female'end# defines Languageenum(:language) dovalue:name=>'English'value:name=>'German'endend

All defined enum classes are stored in ActiveEnum.enum_classes array if you need look them up or iterate over them.

You can make an existing model class behave like an enum class with acts_as_enum

classCountry<ActiveRecord::Baseacts_as_enum:name_column=>'short_name'end

Giving you the familiar enum methods

Country[1]
Country['Australia']
Country.to_select

There is support for Formtastic and SimpleForm to make it easier to use the enum values as select options. The plugins have an almost identical API which is handy. You just need to require the extension for the respective plugin in an initialiser:

Formtastic 2.x:

require'active_enum/form_helpers/formtastic2'

Formtastic <2:

require'active_enum/form_helpers/formtastic'

Or, SimpleForm:

require'active_enum/form_helpers/simple_form'

The input type will be automatically detected for enumerated attributes. You can override with the :as option as normal.

The design allows pluggable backends to be used for stories and retrieving the enum values. At present there are two available, memory or I18n. To change the storage engine you alter the storage config value like so:

ActiveEnum.setupdo|config|config.storage = :i18nend

The memory store is default obviously just stores the values in memory.

The I18n storage backend stores the ids and names is memory still, but retrieves the name text translation any call to the enum public methods.

To set up the locale file, run

railsgactive_enum:locale

This generates the YML locale template in your default language as configured in the application.rb.

Here are some examples of defining enum translations

classSex<ActiveEnum::Basevalue1=>'male'value2=>'female'end

becomes

sex:
male: Male female: Female

For namesapced enums in a model

classPerson<ActiveRecord::Baseenumerate:sexdovalue1=>'male'value2=>'female'endend

nest the translations under the underscored model name

person:
sex:
male: Male female: Female

Copyright © 2009 Adam Meehan, released under the MIT license

About

Define enum classes in Rails and use them to enumerate ActiveRecord attributes, with I18n support

Resources

Stars

0 stars

Watchers

7 watching

Forks

Releases

Packages

Contributors

Languages