Simple role-based authorization library for Ruby on Rails
Rabarber is a role-based authorization library for Ruby on Rails that focuses on controller-level access control. Rather than answering domain questions like “can this user create a post?”, Rabarber answers “can this user access the create post endpoint?”, providing a clean separation between authorization and business logic.
Key Features:
Gem Usage:
Community Resources:
Add Rabarber to your Gemfile:
gem "rabarber"
Install the gem:
bundle install
Generate the migration for role storage (replace users
with your user table name if different):
# For standard integer IDs
rails generate rabarber:roles users
# For UUID primary keys
rails generate rabarber:roles users --uuid
Run the migration:
rails db:migrate
Configure Rabarber in an initializer if customization is needed:
Rabarber.configure do |config|
config.cache_enabled = true # Enable role caching (default: true)
config.current_user_method = :current_user # Method to access current user (default: :current_user)
config.user_model_name = "User" # User model name (default: "User")
end
To clear the role cache manually:
Rabarber::Cache.clear
# Create a new role
Rabarber::Role.add(:admin)
# Rename a role
Rabarber::Role.rename(:admin, :administrator)
Rabarber::Role.rename(:admin, :administrator, force: true) # Force if role is assigned to users
# Remove a role
Rabarber::Role.remove(:admin)
Rabarber::Role.remove(:admin, force: true) # Force if role is assigned to users
# List available roles
Rabarber::Role.names
Rabarber::Role.all_names # All roles grouped by context
# Get users assigned to a role
Rabarber::Role.assignees(:admin)
Your user model is automatically augmented with role management methods:
# Assign roles (creates roles if they don't exist)
user.assign_roles(:accountant, :manager)
# Assign only existing roles
user.assign_roles(:accountant, :manager, create_new: false)
# Revoke specific roles
user.revoke_roles(:accountant, :manager)
# Revoke all roles
user.revoke_all_roles
# Check if user has any of the specified roles
user.has_role?(:accountant, :manager)
# Get user's roles
user.roles
# Get all roles grouped by context
user.all_roles
Include the authorization module and configure protection:
class ApplicationController < ActionController::Base
include Rabarber::Authorization
with_authorization # Enable authorization for all actions
end
class InvoicesController < ApplicationController
with_authorization only: [:update, :destroy] # Selective authorization
end
Authorization requires an authenticated user.
You can also selectively skip authorization:
class TicketsController < ApplicationController
skip_authorization except: [:create, :update, :destroy]
end
Define access rules using grant_access
:
class TicketsController < ApplicationController
# Controller-wide access
grant_access roles: :admin
# Action-specific access
grant_access action: :index, roles: [:manager, :support]
def index
# Accessible to admin, manager, and support roles
end
grant_access action: :destroy, roles: :admin
def destroy
# Accessible to admin role only
end
end
Rules are additive across inheritance chains and for the same actions:
class BaseController < ApplicationController
grant_access roles: :admin # Admin can access everything
end
class InvoicesController < BaseController
grant_access roles: :accountant # Accountant can also access InvoicesController (along with admin)
grant_access action: :index, roles: :manager
grant_access action: :index, roles: :supervisor
# Index is accessible to admin, accountant, manager, and supervisor
end
Omit roles to allow unrestricted access:
class UnrestrictedController < ApplicationController
grant_access # Allow all users
end
class MixedController < ApplicationController
grant_access action: :index # Unrestricted index action
grant_access action: :show, roles: :member # Restricted show action
end
Override when_unauthorized
method to customize unauthorized access behavior:
class ApplicationController < ActionController::Base
include Rabarber::Authorization
with_authorization
private
def when_unauthorized
# Default behavior: redirect back (HTML) or return 403 (other formats)
# Custom behavior example:
head :not_found # Hide existence of protected resources
end
end
Add conditional logic to authorization rules:
class OrdersController < ApplicationController
# Method-based conditions
grant_access roles: :manager, if: :company_manager?, unless: :suspended?
# Proc-based conditions
grant_access action: :show, roles: :client, if: -> { current_user.company_id == Order.find(params[:id]).company_id }
# Dynamic-only rules (no roles required, can be used with custom policies)
grant_access action: :index, if: -> { OrdersPolicy.new(current_user).can_access?(:index) }
private
def company_manager?
current_user.manager_of?(Company.find(params[:company_id]))
end
def suspended?
current_user.suspended?
end
end
All Rabarber methods accept a context
parameter, allowing you to work with roles within specific scopes rather than globally.
# Assign roles within a specific model instance
user.assign_roles(:owner, context: project)
user.assign_roles(:member, context: project)
# Assign roles within a model class (e.g., project admin)
user.assign_roles(:admin, context: Project)
# Check contextual roles
user.has_role?(:owner, context: project)
user.has_role?(:admin, context: Project)
# Get roles within context
user.roles(context: project)
Rabarber::Role.names(context: Project)
class ProjectsController < ApplicationController
# Class-based context
grant_access roles: :admin, context: Project
# Instance-based context (method)
grant_access action: :show, roles: :member, context: :current_project
# Instance-based context (proc)
grant_access action: :update, roles: :owner, context: -> { Project.find(params[:id]) }
private
def current_project
@current_project ||= Project.find(params[:id])
end
end
Handle context changes when models are renamed or removed. These are irreversible data migrations.
# Rename a context class (e.g., when you rename your Project model to Campaign)
migrate_authorization_context!("Project", "Campaign")
# Remove orphaned context data (e.g., when you delete a model entirely)
delete_authorization_context!("DeletedModel")
Include view helpers in your application:
module ApplicationHelper
include Rabarber::Helpers
end
Use conditional rendering based on roles:
<%= visible_to(:admin, :manager) do %>
<div class="admin-panel">
<!-- Admin/Manager content -->
</div>
<% end %>
<%= hidden_from(:guest) do %>
<div class="member-content">
<!-- Content hidden from guests -->
</div>
<% end %>
<!-- With context -->
<%= visible_to(:owner, context: @project) do %>
<button>Delete Project</button>
<% end %>
Have a question or need assistance? Open a discussion in our discussions section for:
Found a bug? Please create an issue with:
Ready to contribute? You can:
Before contributing, please read the contributing guidelines
The gem is available as open source under the terms of the MIT License.
Everyone interacting in the Rabarber project is expected to follow the code of conduct.
Only the latest major version is supported. Older versions are obsolete and not maintained, but their READMEs are available here for reference: