Authorization with CanCanCan in Rails

This article will discuss how to implement authorization in a Ruby on Rails application using CanCanCan. Here’s how to start:

1
2
3
4
rails new cancancan-tutorial
rails g scaffold Post title body:text
gem 'devise'
gem 'cancancan'

Devise is required because CanCanCan needs current_user method defined. Run bundle install, then add a devise user with user_type column.

1
2
rails g devise:install
rails g devise User user_type:string

Add two users in seeds.rb.

1
2
3
4
# db/seeds.rb

User.create(email: 'customer@mintbit.com', password: '123123', password_confirmation: '123123', user_type: 'customer')
User.create(email: 'admin@mintbit.com', password: '123123', password_confirmation: '123123', user_type: 'admin')

Now run rails db:seed, then create an ability.

1
rails g cancan:ability

Before setting ability, define a method that returns either true or false if current user is an admin or not.

1
2
3
4
# app/models/user.rb
def admin?
 user_type == 'admin'
end

Now define an ability.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# app/models/ability.rb

class Ability
 include CanCan::Ability

 def initialize(user)
   user ||= User.new # guest user (not logged in)
   if user.admin?
     can :manage, Post
   else
     can :read, Post
   end
 end
end

In app/controllers/application_controller.rb, handle the error.

1
2
3
4
5
6
7
# app/controllers/application_controller.rb

class ApplicationController < ActionController::Base
 rescue_from CanCan::AccessDenied do |exception|
   redirect_to root_url, :alert => exception.message
 end
end

Now in app/controllers/posts_controller.rb, put these two lines at the top:

1
2
before_action :authenticate_user!
load_and_authorize_resource

Now the admin will be able to create a post but the customer will not. Happy authorizing!