Effective Roles

Assign multiple roles to any User or other ActiveRecord object. Select only the appropriate objects based on intelligent, chainable ActiveRecord::Relation finder methods.

Implements multi-role authorization based on an integer roles_mask field

Includes a mixin for adding authentication for any model.

SQL Finders for returning an ActiveRecord::Relation with all permitted records.

Getting Started

Add to Gemfile:

gem 'effective_roles'

Run the bundle command to install it:

bundle install

Install the configuration file:

rails generate effective_roles:install

The generator will install an initializer which describes all configuration options.


Add the mixin to an existing model:

class Post
  acts_as_role_restricted                  # Singular role, use radio buttons
  acts_as_role_restricted multiple: true   # Multiple roles. use check boxes

Then create a migration to add the :roles_mask column to the model.

rails generate migration add_roles_to_post roles_mask:integer

which will create a migration something like

class AddRolesToPost < ActiveRecord::Migration
  def change
    add_column :posts, :roles_mask, :integer


Defining Roles

All roles are defined in the config/effective_roles.rb initializer. The roles are defined once and may be applied to any acts_as_role_restricted model in the application.


Assign roles:

post.roles = [:admin, :superadmin]

See if an object has been assigned a specific role:

=> true

=> true

post.is_any?(:editor, :superadmin)
=> true

=> [:admin, :superadmin]

Compare against another acts_as_role_restricted object:

post = Post.new()
post.roles = :admin

user = User.new()
user.roles = nil

=> false  # Post requires the :admin role, but User has no admin role
post.roles = :superadmin
user.roles = :admin

=> false  # User does not have the superadmin role
post.roles = :admin
user.roles = [:superadmin, :admin]

=> true  # User has required :admin role

Finder Methods

Find all objects that have been assigned a specific role (or roles). Will not return posts that have no assigned roles (roles_mask = 0 or NULL)

Post.with_role(:admin, :superadmin)   # Can pass as an array if you want

Find all objects that are appropriate for a specific role. Will return posts that have no assigned roles


These are both ActiveRecord::Relations, so you can chain them with other methods like normal.

Assignable Roles

Specifies which roles can be assigned to a resource by a specific user.

See the initializers/effective_roles.rb for more information.

  config.assignable_roles = {
    :superadmin => [:superadmin, :admin, :member], # Superadmins may assign any resource any role
    :admin => [:admin, :member],                   # Admins may only assign the :admin or :member role
    :member => []                                  # Members may not assign any roles

When using assignable roles, you must assign the acts_as_role_restricted resource a current_user when saving changes to the roles or roles mask:

You can do this in one of three ways:

  1. Setting resource.current_user = current_user in your controller update action directly.
  2. Add before_action -> { @thing.current_user = current_user } to your ApplicationController
  3. Using Effective::CrudController to do this automatically.

This restriction is only applied when running within the rails server. Not on rails console or db:seeds.

Form Helper

If you pass current_user (or any acts_as_role_restricted object) into these helpers, only the assignable_roles will be displayed.


Depending on your acts_as_role_restricted multiple: value:

effective_form_with(model: @user) do |f|
  = f.checks :roles, EffectiveRoles.roles_collection(f.object, current_user)
effective_form_with(model: @user) do |f|
  = f.radios :roles, EffectiveRoles.roles_collection(f.object, current_user)


simple_form_for @user do |f|
  = f.input :roles, collection: EffectiveRoles.roles_collection(f.object, current_user), as: :check_boxes
simple_form_for @user do |f|
  = f.input :roles, collection: EffectiveRoles.roles_collection(f.object, current_user), as: :radio_buttons

Strong Parameters

Make your controller aware of the passed parameters:

def permitted_params

The actual permitted parameters are:

roles: []


Use the effective_roles_summary view helper to output a list of roles and descriptions.

effective_roles_summary(user) # any acts_as_role_restricted object

Summary table

Use the effective_roles_summary_table view helper to output a table of the actual permission levels for each role and ActiveRecord object combination.

You can customize the helper function with the following keys: roles, only, except, plus and additionally

effective_roles_summary_table(roles: [:admin, :superadmin], only: [Post, Event])
effective_roles_summary_table(except: [Post, User])
effective_roles_summary_table(plus: [Reports::PostReport]) # Add a non ActiveRecord object to the output, sorted with the other model names
effective_roles_summary_table(additionally: [Reports::PostReport]) # Add a non ActiveRecord object to the output, after the other models
effective_roles_summary_table(plus: {post_report: :export}) # A custom permission based on a symbol

You can override the effective_roles_authorization_label(klass) method for better control of the label display.

Bitmask Implementation

The underlying role information for any acts_as_role_restricted ActiveRecord object is stored in that object's roles_mask field.

roles_mask is an integer, in which each power of 2 represents the presence or absense of a role.

If we have the following roles defined:

EffectiveRoles.setup do |config|
  config.roles = [:superadmin, :admin, :betauser, :member]

Then the following will hold true:

user = User.new()

=> []

=> 0

user.roles = [:superadmin]
=> 1

user.roles = [:admin]
=> 2

user.roles = [:betauser]
=> 4

user.roles = [:member]
=> 8

As well:

user.roles = [:superadmin, :admin]
=> 3

user.roles = [:superadmin, :betauser]
=> 5

user.roles = [:admin, :member]
=> 10

user.roles = [:superadmin, :admin, :betauser, :member]
=> 15

Keep in mind, when using this gem you should never be working directly with the roles_mask field.

All roles are get/set through the roles and roles= methods.


MIT License. Copyright Code and Effect Inc.


This model implements the https://github.com/ryanb/cancan/wiki/Role-Based-Authorization multi role based authorization based on the roles_mask field


  1. Fork it
  2. Create your feature branch (git checkout -b my-new-feature)
  3. Commit your changes (git commit -am 'Add some feature')
  4. Push to the branch (git push origin my-new-feature)
  5. Bonus points for test coverage
  6. Create new Pull Request