Rails 4’s Awesome enums

In Rails 4 enum was introduced to support a feature that people were building by hand or by gem. What enum does for you is it associates a symbol list for you to reference which will be stored in the database as an integer. So :cow could be 0 and :dog could be 1 in an enum of [:cow, :dog] . But enum is far more helpful that that. It builds scopes and boolean checker methods.

For example. Lets create a Flower object and we’ll have kinds and colors as enums.

First we generate the model.

rails g model Flower kind:integer:index color:integer:index 1 2 rails g model Flower kind : integer : index color : integer : index

Then we update app/models/flower.rb

app/models/flower.rb # app/models/flower.rb class Flower < ActiveRecord::Base enum kind: [:rose, :tulip] enum color: [:blue, :red, :yellow, :white] end 1 2 3 4 5 6 # app/models/flower.rb class Flower < ActiveRecord :: Base enum kind : [ : rose , : tulip ] enum color : [ : blue , : red , : yellow , : white ] end

Make sure you migrate.

rake db:migrate 1 2 rake db : migrate

And now all the hard work has been done for you.

You can create a blue rose in two different ways. With scopes, or with attributes.

# By Scopes Flower.blue.rose.create # By Attributes Flower.create(kind: Flower.kinds[:rose], color: Flower.colors[:blue]) 1 2 3 4 5 6 # By Scopes Flower . blue . rose . create # By Attributes Flower . create ( kind : Flower . kinds [ : rose ] , color : Flower . colors [ : blue ] )

As you can see I used the plural name on the class of Flower for setting the attribute values. The plural named method is a Hash of the enum symbol names to the index of their placement in the originally defined Array. So kinds[:rose] will return 0 for the attribute to be written to the database since it was the first item in the enum defined.

And you can access them by the same scopes (and scopes work in any order)

Flower.rose.blue.count # => 2 1 2 3 Flower . rose . blue . count # => 2

As I had mentioned earlier enum will add boolean checkers for every single enum option.

Flower.first.tulip? # => false Flower.first.rose? # => true Flower.first.yellow? # => false Flower.first.blue? # => true 1 2 3 4 5 6 7 8 9 Flower . first . tulip ? # => false Flower . first . rose ? # => true Flower . first . yellow ? # => false Flower . first . blue ? # => true

And you can forcefully change them with a bang method.

Flower.first.color # "blue" Flower.first.blue? # => true Flower.first.yellow! Flower.first.color # "yellow" Flower.first.yellow? # => true Flower.first.blue? # => false 1 2 3 4 5 6 7 8 9 10 11 12 Flower . first . color # "blue" Flower . first . blue ? # => true Flower . first . yellow ! Flower . first . color # "yellow" Flower . first . yellow ? # => true Flower . first . blue ? # => false

If you look at the record’s attributes you can see that the enum‘s are stored as integers. The integers are the index of the Array in which you declared the enum. So you can add new items to the end of the enum Array, but don’t change the ordering.

Flower.first.attributes # => {"id"=>1, "kind"=>0, "color"=>2,"created_at"=>...,"updated_at"=>...} 1 2 3 Flower . first . attributes # => {"id"=>1, "kind"=>0, "color"=>2,"created_at"=>...,"updated_at"=>...}

To check whether an enum value has been set for any of the enum fields just use a boolean check on the enum name.

Flower.first.color? # => true Flower.first.kind? # => true 1 2 3 4 5 Flower . first . color ? # => true Flower . first . kind ? # => true

Summary

As you can see enum has saved us a lot of work by defining many scopes and helper methods. This comes in to be pretty handy. As a consequence though you can’t use conflicting names between any enum or ActiveRecord methods. So you may have to be clever for some names to use. I really like having the convenience that enum adds. And now you have this power tool in your tool set! ^_^

Please share, I’d love to hear about them. Please feel free to comment, share, subscribe to my RSS Feed, and follow me on twitter @6ftdan!

God Bless!

-Daniel P. Clark

Image by Hernán García Crespo via the Creative Commons Attribution 2.0 Generic License.