0
0
RailsHow-ToBeginner · 4 min read

How to Use Cancancan for Authorization in Ruby on Rails

Use cancancan by defining user abilities in an Ability class and checking permissions in controllers or views with authorize! or can?. Install the gem, generate the ability file, then specify what users can do based on roles or conditions.
📐

Syntax

The core of Cancancan is the Ability class where you define user permissions using can and cannot methods. You specify the action (like :read, :create), the resource (model class), and optional conditions.

In controllers or views, use authorize! :action, @resource to enforce permissions or can? :action, @resource to check if a user can perform an action.

ruby
class Ability
  include CanCan::Ability

  def initialize(user)
    user ||= User.new # guest user
    if user.admin?
      can :manage, :all
    else
      can :read, Article
      can :create, Comment
      cannot :destroy, Article
    end
  end
end
💻

Example

This example shows how to set up Cancancan in a Rails app with a simple Ability class and how to use authorize! in a controller to restrict access.

ruby
# Gemfile
# Add cancancan gem

gem 'cancancan', '~> 3.3'

# Run bundle install

# Generate Ability class
rails g cancan:ability

# app/models/ability.rb
class Ability
  include CanCan::Ability

  def initialize(user)
    user ||= User.new
    if user.admin?
      can :manage, :all
    else
      can :read, Article
      can :create, Comment
      cannot :destroy, Article
    end
  end
end

# app/controllers/articles_controller.rb
class ArticlesController < ApplicationController
  before_action :set_article, only: [:show, :destroy]

  def show
    authorize! :read, @article
    # show article
  end

  def destroy
    authorize! :destroy, @article
    @article.destroy
    redirect_to articles_path
  end

  private

  def set_article
    @article = Article.find(params[:id])
  end
end
Output
If a non-admin user tries to destroy an article, Cancancan raises CanCan::AccessDenied and prevents the action.
⚠️

Common Pitfalls

  • Not handling CanCan::AccessDenied exceptions, which causes app crashes instead of friendly error messages.
  • Forgetting to define abilities for guest users (user ||= User.new is important).
  • Using authorize! without loading the resource first can cause errors.
  • Mixing authorization logic in controllers instead of centralizing in Ability class.
ruby
# Wrong: No guest user handling
class Ability
  include CanCan::Ability

  def initialize(user)
    if user&.admin?
      can :manage, :all
    end
  end
end

# Right: Handle guest user
class Ability
  include CanCan::Ability

  def initialize(user)
    user ||= User.new
    if user.admin?
      can :manage, :all
    else
      can :read, Article
    end
  end
end
📊

Quick Reference

MethodPurposeExample
canDefine allowed action on resourcecan :read, Article
cannotDefine disallowed actioncannot :destroy, Article
authorize!Check permission and raise error if deniedauthorize! :update, @article
can?Check permission, returns true/falsecan? :create, Comment
load_and_authorize_resourceController helper to load and authorizebefore_action :load_and_authorize_resource

Key Takeaways

Define all user permissions centrally in the Ability class using can and cannot.
Use authorize! in controllers to enforce permissions and handle AccessDenied exceptions gracefully.
Always handle guest users by initializing user with User.new in Ability.
Use load_and_authorize_resource to simplify controller authorization.
Test authorization rules to avoid unexpected access or errors.