Authorization with CanCan
CanCan is a simple authorization strategy for Rails which is decoupled from user roles. All permissions are stored in a single location.
Getting started with CanCan
Section titled “Getting started with CanCan”CanCan is a a popular authorization library for Ruby on Rails which restricts user access to specific resources. The latest gem (CanCanCan) is a continuation of the dead project CanCan.
Permissions are defined in the Ability class and can be used from controllers, views, helpers, or any other place in the code.
To add authorization support to an app, add the CanCanCan gem to the Gemfile:
gem 'cancancan'Then define the ability class:
class Ability include CanCan::Ability
def initialize(user) endendThen check authorization using load_and_authorize_resource to load authorized models into the controller:
class ArticlesController < ApplicationController load_and_authorize_resource
def show # @article is already loaded and authorized endendauthorize! to check authorization or raise an exception
def show @article = Article.find(params[:id]) authorize! :read, @articleendcan? to check if an object is authorized against a particular action anywhere in the controllers, views, or helpers
<% if can? :update, @article %> <%= link_to "Edit", edit_article_path(@article) %><% end %>Note: This assumes the signed user is provided by the current_user method.
Handling large number of abilities
Section titled “Handling large number of abilities”Once the number of abilities definitions start to grow in number, it becomes more and more difficult to handle the Ability file.
The first strategy to handle these issue is to move abilities into meaningful methods, as per this example:
class Ability include CanCan::Ability
def initialize(user) anyone_abilities
if user if user.admin? admin_abilities else authenticated_abilities end else guest_abilities end end
private
def anyone_abilities # define abilities for everyone, both logged users and visitors end
def guest_abilities # define abilities for visitors only end
def authenticated_abilities # define abilities for logged users only end
def admin_abilities # define abilities for admins only endendOnce this class grow large enough, you can try breaking it into different classes to handle the different responsibilities like this:
class Ability include CanCan::Ability
def initialize(user) self.merge Abilities::Everyone.new(user)
if user if user.admin? self.merge Abilities::Admin.new(user) else self.merge Abilities::Authenticated.new(user) end else self.merge Abilities::Guest.new(user) end endendand then define those classes as:
module Abilities class Guest include CanCan::Ability
def initialize(user) # Abilities for anonymous visitors only end endendand so on with Abilities::Authenticated, Abilities::Admin or any other else.
Defining abilities
Section titled “Defining abilities”Abilities are defined in the Ability class using can and cannot methods. Consider the following commented example for basic reference:
class Ability include CanCan::Ability
def initialize(user) # for any visitor or user can :read, Article
if user if user.admin? # admins can do any action on any model or action can :manage, :all else # regular users can read all content can :read, :all # and edit, update and destroy their own user only can [:edit, :destroy], User, id: user_id # but cannot read hidden articles cannot :read, Article, hidden: true end else # only unlogged visitors can visit a sign_up page: can :read, :sign_up end endendQuickly test an ability
Section titled “Quickly test an ability”If you’d like to quickly test if an ability class is giving the correct permissions, you can initialize an ability in the console or on another context with the rails environment loaded, just pass an user instance to test against:
test_ability = Ability.new(User.first)test_ability.can?(:show, Post) #=> trueother_ability = Ability.new(RestrictedUser.first)other_ability.cannot?(:show, Post) #=> trueMore information: https://github.com/ryanb/cancan/wiki/Testing-Abilities
Remarks
Section titled “Remarks”Before using CanCan don’t forget to create Users either by devise gem or manually. To get maximum functionality of CanCan do create an Admin user.