Active Record enums in Ruby on Rails 4.1

I was recently working on a Rails app that required role-based authorization for its users. Basically, the application would need the ability to check to see if the user had the proper credentials to access certain features of the site.

I’ve typically handled this in the past by either adding an admin boolean column in the Users table so I could simply call @user.admin? to check to see if the user is an admin or not, or for situations which require multiple levels of authorization (or the ability to give a user more than one set of privileges at a time), adding a many-to-many association between the User model and another model called Role. This many-to-many association also requires a join table called role_user. The latter approach is obviously more complex and requires the creation of several helper methods to become convenient to use.

Since I was using Rails 4.1 for this project and because each user only needed to be granted one user role at a time, I figured I would give the new ActiveRecord::Enum feature a try. Rails now provides a really simple way to quickly add attributes and a bunch of associated helper methods to an Active Record class.

For example, when I added this one line to my User model:

class User < ActiveRecord::Base
  enum role: [:reader, :contributor, :admin]
end

I got all of these convenience methods for free:

user.contributor!
user.contributor? # => true
user.role  # => "contributor"

user.admin!
user.contributor? # => false
user.admin? # => true
user.role # => "admin"

User.admin # => relation for all admin users

User.roles # => { "reader" => 0, "contributor" => 1, "admin" => 2 }

The only additional thing you need to get these Active Record enums working is a migration to add the attribute to the model, in this case adding role to User. Notice that this column is an integer value, which is mapped to the index of each enum value:

$ rails g migration AddRoleToUsers role:integer

which automatically generates:

class AddRoleToUsers < ActiveRecord::Migration
  def change
    add_column :users, :role, :integer, default: 0
  end
end

I also set the first declared status be the default as recommended in the documentation.

And that’s all there is to it! You can find more information in the Rails Edge Guides 4.1 Release Notes.

2 Comments

  1. confi
    November 28, 2014

    I think the migration shown there is from another migration, its creating a table called conversations instead of add a role column to the users table.

    rails g migration AddRoleToUsers role:integer

    create_table :conversations do |t|
    t.column :status, :integer, default: 0
    end

  2. jkasiewicz
    May 9, 2015

    Thanks for letting me know! This has been corrected.

Leave a Reply

Your email address will not be published. Required fields are marked *