Introduction

edit

CanCan is an authorization library for Ruby on Rails which gives restrictions on both the resources and different actions to a given user to access within each resource. All the restrictions are specified in the same "ability.rb" files ( folder "models" ) and do not need to be copied across different controllers, views and database queries.[1]

"Cancan" gem is no longer maintained and updated any more. "Cancancan" gem is the authorization library for Ruby on Rails which is under maintenance.

Installation[2]

edit

Install in Rails 3

edit

In Rails 3[3], it is easy to implement by including the following code into the Gemfile and then running the "bundle install" command in the terminal.

gem "cancan"

Install in Rails 2

edit

In Rails 2[4], simply add the code to the "environment.rb" file.

config.gem "cancan"

Install as a Plugin

edit

As a substitute, it can be installed as a plugin.

rails plugin install git://github.com/ryanb/cancan.git

Basic Operations

edit

In "ability.rb" file ("Ability" class), user access permissions are defined .

Create "Ability" Class[5]

edit

CanCan 1.5 and latter versions include a Rails 3 generator for creating this class in the "models" folder. "Ability" class is created by run the following command in the terminal.

rails g cancan:ability

There will be a file called "ability.rb" created in the path of "app/models/ability.rb", in which we can define all the permissions. The initialized "Ability" class is

class Ability
  include CanCan::Ability

    def initialize(user)
    
  end
end

The current user is passed to the method in the initialization method. Any of the user attributes can be used to define and modify the permissions of the user. No assumption are made by CanCan about how roles are handled in your application.

Permission Define Structure

edit

In the "Ability" class, usually we use conditional statement like "if...else..." to define all the permissions.

For example, here we have the user.admin and normal user types for the project and different permissions for them are defined separately in the conditional statement.

class Ability
  include CanCan::Ability

    def initialize(user)
    if user.admin?
        # permissions for the admin users
    else
        # permissions for the other users
    end
    
  end
end

Define Abilities & Authorization[6]

edit

The current user's permissions can be defined using the "can" and "cannot" methods.

"can" method

edit

The "can" method is used to define permissions, which requires two arguments. The first argument is the action you're setting the permission for, the second one is the class of object you're setting it on.

For example, here we define the current user can edit the article.

can :update, Article

Common actions include ":read", ":create", ":update" and ":destroy", but it can be anything.

You can also pass an array for either of these parameters to match any one.

For example, here the user will have the ability to read or update both questions and answers.

can [:read, :update], [Question, Answer]

A hash of conditions can be passed to give further restricts which records this permission applies to. For example, here the user will only have permission to update project which is active and belongs to the user.

can :update, Project, :active => true, :user_id => user.id

"cannot" method

edit

The "cannot" method takes the same arguments as "can" method and defines the actions the user is not allowed to access. This is normally done after a more generic "can" call, like ":manage".

For example, here the current user will have the ability to do everything except destroy the project.

can :manage, Project
cannot :destroy, Project

Check Abilities & Authorization[7]

edit

After defining abilities, you can use the "can?" and "cannot?" methods in the controller or view to check the user's permission for a given action and object.

For example, here we check whether the current user can or cannot destroy the project using the "can?" and "cannot?" methods. or either the "can?" or "cannot?" methods.

can? :destroy, @project
cannot? :destroy, @project

Note: If a block or hash of conditions exist in the definition of the abilities, they will be ignored when checking on a class. For example, here we define a user can update the project when the project is active, however when we check whether the user can update project, it will always return "true".

can :update, Project, :active => true
can? :update, Project                             # always returns true

Applications of Abilities & Authorization[8]

edit

Using the conditional statements, we can check the permissions using "can?" and "cannot?" method.

For example, here we check whether the current user have the permission to update the article or not. If true, then we show the link "Edit" to the edit path.

<% if can? :update, @article %>
  <%= link_to "Edit", edit_article_path(@article) %>
<% end %>

Force Authorization Check

edit

Although as we can use "can?" and "cannot?" method to check authorization and decide whether to show the link to action in the webpage, the actual page of the action in the webpage exists, we may manually input the URL such as "../projects/(projects id)/edit" in the web browser to avoid the Authorization Check and gain the access to edit the project.

To solve this problem, you should always remember to go to the specific action you want to authorize and force authorization check.

For example, here we force the authorization check in the show action to make sure every time the show action need to go through a check. If the user have no permission to edit the project, even if he enter the URL as "../projects/(projects id)/edit" in the web browser, the user will have to go through the authorization check and have the result as permission denied.

def show
    authorize! :update, @project
end

Handle Unauthorized Access[9]

edit

A CanCan::AccessDenied exception will be raised if the user authorization fails. You can catch this exception and modify its behavior in the controller.

For example, here we redirect the webpage to the "projects_url" and show the authorization fails message.

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

Exception: Cancan::Error[10]

edit

CanCan::AccessDenied

edit

This error occurs when a user isn't allowed to access a given controller action. This usually happens within a call to ControllerAdditions#authorize!.

raise CanCan::AccessDenied.new("Not authorized!", :read, Article)

This exception can also be raised manually if more custom behavior is needed.

raise CanCan::AccessDenied.new("Not authorized!", :read, Article)

CanCan::AuthorizationNotPerformed

edit

This error occurs when users use check_authorization without calling authorized!

CanCan::ImplementationRemoved

edit

This error is raised when removed code is called, an alternative solution is provided in message.

CanCan::NotImplemented

edit

This error is raised when the behavior is not implemented, usually used in an abstract class.

Version History[11]

edit

The following table is based on information from rubygems.org.

Version Release date Minimum

RubyGems

Version

Size Development Dependences
rails rr rspec supermodel
0.1 Nov. 2009 1.2 9.0KB n/a n/a n/a n/a
0.2 Nov. 2009 9.5KB
1.0 Dec. 2009 13.5KB
1.1 Apr. 2010 1.3.4 17.5KB
1.2 Jul. 2010 19.5KB
1.3 Aug. 2010 22.0KB
1.4 Sep. 2010 27.0KB
1.5 Jan. 2011 31.5KB 3.0.0 0.10.11 2.1.0 0.1.4
1.6.0 Mar. 2011 33.5KB
1.6.7 Oct. 2011 35.0KB 3.0.9 2.6.0
1.6.10 May. 2013 38.5KB

References

edit
  1. ^ "Cancan".
  2. ^ "Installation of Cancan".
  3. ^ "Rails 3".
  4. ^ "Rails 2".
  5. ^ "Define_Abilities".
  6. ^ "defining-abilities".
  7. ^ "checking-abilities".
  8. ^ "Check_Abilities___Authorization".
  9. ^ "Handle_Unauthorized_Access".
  10. ^ "Error".
  11. ^ "version history".