CanCanCan
Authorization library for Ruby on Rails — defines user abilities (what actions users can perform on resources) in a central Ability class. CanCanCan: can :read, Agent (user can read agents), can :manage, Agent, user_id: user.id (user can manage their own agents), cannot :delete, Agent (overrides previous allow). Controller integration: authorize! :read, @agent raises CanCan::AccessDenied if unauthorized; load_and_authorize_resource macro auto-loads and authorizes resource. View helpers: can?(:edit, @agent) for conditional UI rendering. Successor to CanCan (which is unmaintained), community-maintained continuation.
Score Breakdown
⚙ Agent Friendliness
🔒 Security
Authorization is security-critical — ensure Ability class correctly restricts agent resource access. always use authorize! or load_and_authorize_resource; forgetting authorization check is security vulnerability. accessible_by scope prevents unauthorized agent data access in list views. Test authorization with negative cases.
⚡ Reliability
Best When
You're building a Rails agent application with multiple user roles and resource-level permissions — CanCanCan's central Ability class makes authorization rules readable and testable.
Avoid When
You're building API-only services with JWT (Pundit is cleaner), you need attribute-level permissions, or you prefer policy object pattern over central Ability class.
Use Cases
- • Role-based agent access control — can :manage, Agent if user.admin?; can :read, Agent if user.operator?; can :create, Agent, :update if user.developer? defines tiered agent permissions
- • Agent resource ownership enforcement — can :manage, AgentTask, user_id: user.id restricts agent task management to the owning user without manual controller checks
- • Conditional agent UI with can? helper — <%= link_to 'Delete Agent', agent, method: :delete if can?(:delete, agent) %> shows delete button only to authorized users
- • Bulk authorization with load_and_authorize_resource — class AgentsController; load_and_authorize_resource automatically loads @agent and authorizes every controller action based on Ability class
- • Agent feature flags via abilities — can :use_experimental_agent if user.beta_tester? enables feature-flagged agent capabilities through authorization system
Not For
- • API-only services with JWT — CanCanCan integrates with Rails sessions; for API services using stateless JWT, attribute-based access control (ABAC) or Pundit's policy objects are cleaner
- • Complex attribute-level permissions — CanCanCan is action-based (can :read, Agent); for column-level permissions or complex conditional attribute access, use Pundit with dedicated policy objects
- • Non-Rails Ruby apps — CanCanCan assumes Rails conventions; use Pundit for non-Rails Ruby agent services needing authorization
Interface
Authentication
Authorization library — works with any authentication (Devise, JWT, etc.). Ability class initialized with current_user from application auth.
Pricing
CanCanCan is MIT licensed, maintained by CanCanCommunity. Free for all use.
Agent Metadata
Known Gotchas
- ⚠ Order of can/cannot matters — CanCanCan processes abilities in order; can :manage, Agent followed by cannot :delete, Agent correctly prevents delete; reversing order (cannot then can) results in can overriding cannot; agent permission definitions must be ordered from general to specific
- ⚠ load_and_authorize_resource needs custom finder for non-standard IDs — default load_and_authorize_resource uses params[:id] with Agent.find; custom: load_and_authorize_resource :agent, find_by: :slug for agents found by slug; wrong finder causes ActiveRecord::RecordNotFound instead of 403
- ⚠ Ability conditions generate SQL scope — can :read, Agent, user_id: user.id generates Agent.where(user_id: user.id) accessible scope; current_ability.accessible_by(current_user) returns scoped collection; condition hash must match database column names, not Ruby attribute names
- ⚠ cannot is not inverse of can for SQL conditions — cannot :manage, Agent, user_id: other_user.id doesn't generate NOT WHERE query; use explicit cannot with block for negative SQL conditions; agent permission SQL generation has edge cases with complex conditions
- ⚠ Ability class initializes per request — Ability.new(current_user) runs on each request; heavy computation (database queries) in Ability#initialize slows all agent controller actions; cache role lookups with memoization in Ability
- ⚠ Testing abilities requires CanCan::Matchers — RSpec matchers: is_expected.to be_able_to(:read, agent); requires require 'cancan/matchers' in spec_helper; testing ability class separately from controllers gives faster agent authorization unit tests
Alternatives
Full Evaluation Report
Detailed scoring breakdown, competitive positioning, security analysis, and improvement recommendations for CanCanCan.
Scores are editorial opinions as of 2026-03-06.