Skip to content

Repository files navigation

SimpleEnum

Gem VersionBuild StatusCode Climate

Unobtrusive enum-like fields for ActiveRecord and Ruby, brings enums functionality to ActiveRecord and Mongoid models (built for Rails 4+).

Since version 2.0, simple_enum is no longer compatible with Rails 3.x or Ruby 1.8, use version 1.6 instead: https://github.com/lwe/simple_enum/tree/legacy-1.x

Note: a recent search on github for enum turned out, that there are many, many similar solutions. In fact starting with Rails 4.1, there's ActiveRecord::Enum which provides some of the functionality, but is IMHO pretty limited and too strict in the defaults it provides.

ActiveRecord Quick start

Add this to a model:

classUser < ActiveRecord::Baseas_enum:gender,female: 1,male: 0end

Then create the required gender_cd column using migrations:

classAddGenderColumnToUser < ActiveRecord::Migrationdefself.upadd_column:users,:gender_cd,:integerenddefself.downremove_column:users,:gender_cdendend

Mongoid Quick start

Due to the dependency on ActiveModel 4.x, the Mongoid integration is only available for mongoid 4.0.0 (which is at beta1 at the moment). If you intend to use simple_enum with another version of mongoid, use version 1.6 instead.

Load mongoid support in the Gemfile:

gem'simple_enum','~> 2.3.0',require: 'simple_enum/mongoid'

Add this to a model:

classUserincludeMongoid::DocumentincludeSimpleEnum::Mongoidas_enum:gender,female: 1,male: 0end

The primary difference between AR and mongoid is, that additionaly a field is added to mongoid automatically, the field can be customized by setting field: option, or disabled by setting field: false.

Working with enums

Now it's possible to pull some neat tricks on the new column, yet the original db column (gender_cd) is still intact and not touched by anything.

jane=User.newjane.gender=:femalejane.female?# => truejane.male?# => falsejane.gender# => :femalejane.gender_cd# => 1

Easily switch to another value using the bang methods, this does not save the record, only switch the value.

joe=User.newjoe.male!# => :malejoe.gender# => :malejoe.gender_cd# => 0

Accessing actual enum values is possible at the class level:

User.genders# => #<SimpleEnum::Enum:0x0....>User.genders[:male]# => 0User.genders.values_at(:male,:female)# => [0, 1] (since 2.1.0)User.females# => #<ActiveRecord::Relation:0x0.....> (WHERE gender_cd = 1)

By default, scope names are generated as pluralized forms of the defined enum values e.g.

classBooking < ActiveRecord::Baseas_enum:status,%i{activecancelledpending}end

would generate the following:

Booking.actives# => #<ActiveRecord::Relation:0x0.....> (WHERE status_cd = 1)Booking.cancelleds# => #<ActiveRecord::Relation:0x0.....> (WHERE status_cd = 2)Booking.pendings# => #<ActiveRecord::Relation:0x0.....> (WHERE status_cd = 3)

By setting pluralize_scopes: false will not generate pluralized versions of scopes e.g.

classBooking < ActiveRecord::Baseas_enum:status,%i{activecancelledpending},pluralize_scopes: falseend

would generate the following:

Booking.active# => #<ActiveRecord::Relation:0x0.....> (WHERE status_cd = 1)Booking.cancelled# => #<ActiveRecord::Relation:0x0.....> (WHERE status_cd = 2)Booking.pending# => #<ActiveRecord::Relation:0x0.....> (WHERE status_cd = 3)

Wait, there's more!

  • Too tired of always adding the integer values? Try:

    classUser < ActiveRecord::Baseas_enum:status,%i{deletedactivedisabled}# translates to: { deleted: 0, active: 1, disabled: 2 }end

    Disclaimer: if you ever decide to reorder this array, beware that any previous mapping is lost. So it's recommended to create mappings (that might change) using hashes instead of arrays. For stuff like gender it might be probably perfectly fine to use arrays though.

  • You can store as string values instead of integer values if your database column has the type string or text:

    classUser < ActiveRecord::Baseas_enum:status,[:deleted,:active,:disabled],map: :stringendUser.create!(status: :active)#=> #<User id: 1, status_cd: "active">
  • Want to use SimpleEnum in an ActiveModel, or other class, just add:

    classMyModelextendSimpleEnum::Attributeattr_accessor:gender_cdas_enum:gender,[:male,:female]end
  • Maybe you've columns named differently than the proposed {column}_cd naming scheme, feel free to use any column name by providing an option:

    classUser < ActiveRecord::Baseas_enum:gender,[:male,:female],source: :sexend

    Starting with 2.0 it's possible to use the same source name as column name.

  • By default ActiveRecord dirty methods are generated:

    user=User.male.firstuser.gender=:femaleuser.gender_was# => :male
  • Need to provide custom options for the mongoid field, or skip the automatically generated field?

    # skip field generationfield:gender_cd# <- create field manually (!)as_enum:gender,[:male,:female],field: false# custom field options (directly passed to Mongoid::Document#field)as_enum:gender,[:male,:female],field: {:type=>Integer,:default=>1}
  • To validate enum values simply make use of a validates :gender, presence: true validation. If an invalid value is assigned, the gender is set to nil by default.

  • If the shortcut methods (like female?, female! or User.male) conflict with something in your class, it's possible to define a prefix:

    classUser < ActiveRecord::Baseas_enum:gender,%w{malefemale},prefix: trueendjane=User.newgender: :femalejane.gender_female?# => trueUser.gender_females# => <ActiveRecord::Relation...WHERE gender_cd = 1.>

    The :prefix option not only takes a boolean value as an argument, but instead can also be supplied a custom prefix, so with prefix: 'foo' all shortcut methods would look like: foo_<symbol>

  • To define which methods are generated it's possible to set with: option, by default with: is set to [:attribute, :dirty, :scope].

    1. :attribute - generates the male? and male! accessor methods
    2. :dirty - adds the gender_was and gender_changed? dirty methods
    3. :scope - adds the class level scopes, if the scope method is present
  • By default the value is set to nil when the user sets an invalid value, this behavior can be changed by setting the accessor: option. At the moment there are three different behaviors:

    1. :default - which sets the value simply to nil
    2. :whiny - raises an ArgumentError when trying to set an invalid value
    3. :ignore - keeps the existing value
    classUser < ActiveRecord::Baseas_enum:gender,%w{malefemale},accessor: :whinyendUser.new(gender: "dunno")# => raises ArgumentError

    See lib/simple_enum/accessors/* for more.

  • To define any option globally, e.g. never generating dirty methods, create an initializer and add:

    # See lib/simple_enum.rb for other optionsSimpleEnum.with=[:attribute,:scope]

View Helpers

Require translated enum values? See SimpleEnum::ViewHelpers for more details and functions. Disclaimer: these methods are release candidate quality so expect them to change in future versions of SimpleEnum.

  • Translate the current value in a view:

    translate_enumuser,:gender# => "Frau" # assuming :de and translations existteuser,:gender# translate_enum is also aliased to te

    Provide translations in the i18n yaml file like:

    de:
    enums:
    gender:
    female: 'Frau'male: 'Mann'
  • Build a select tag with a translated dropdown and symbol as value:

    select:user,:gender,enum_option_pairs(User,:gender)
  • ...and one with the index as value:

    select:user,:gender_cd,enum_option_pairs(User,:gender,true)

Extensions

simple_enum provides hooks to extend its functionality, starting with 2.3.0 the following extensions can be used:

Best practices

Do not use values named after existing, or well known method names, like new, create etc.

# BAD, conflicts with Rails ActiveRecord Methods (!)as_enum:handle,[:new,:create,:update]# GOOD, prefixes all methodsas_enum:handle,[:new,:create,:update],prefix: true

Searching for certain values by using the finder methods:

User.females# => returns an ActiveRecord::Relation

Contributors

License & Copyright

Copyright (c) 2011-2015 by Lukas Westermann, Licensed under MIT License (see LICENSE file)

About

Simple enum-like field support for ActiveModel (including validations and i18n)

Resources

Stars

415 stars

Watchers

8 watching

Forks

Releases

Packages

Used by

Contributors

Languages