This is a simple authorization solution for Ruby on Rails to restrict what a given user is allowed to access in the application. This is completely decoupled from any role based implementation allowing you to define user roles the way you want. All permissions are stored in a single location and not duplicated across the controller, view, and database.
This assumes you already have authentication (such as Authlogic[http://github.com/binarylogic/authlogic] or Devise[http://github.com/plataformatec/devise]) which provides a +current_user+ model.
Setting this for every action can be tedious, therefore the load_and_authorize_resource method is also provided to automatically authorize all actions in a RESTful style resource controller. It will set up a before filter which loads the resource into the instance variable and authorizes it.
If the user authorization fails, a CanCan::AccessDenied exception will be raised. You can catch this and modify its behavior in the ApplicationController.
As shown above, the Ability class is where all user permissions are defined. The user model is passed into the initialize method so you are free to modify the permissions based on the user's attributes. This way CanCan is completely decoupled with how you choose to handle roles.
The "can" method accepts two arguments, the first one is the action you're setting the permission for, the second one is the class of object you're setting it on.
can :update, Article
You can pass an array for either of these parameters to match any one.
can [:update, :destroy], [Article, Comment]
In this case the user has the ability to update or destroy both articles and comments.
If the block returns true then the user has that :update ability for that project, otherwise he will be denied access. It's possible for the passed in model to be nil if one isn't specified, so be sure to take that into consideration.
The downside to using a block is that it cannot be used to generate conditions for database queries.
As mentioned in the Getting Started section, you can use the +load_and_authorize_resource+ method in your controller to load the resource into an instance variable and authorize it. If you have a nested resource you can specify that as well.
load_and_authorize_resource :nested => :author
You can also pass an array to the :+nested+ attribute for deep nesting.
If you want to customize the loading behavior on certain actions, you can do so in a before filter.
Sometimes you need to restrict which records are returned from the database based on what the user is able to access. This can be done with the +accessible_by+ method on any Active Record model. Simply pass it the current ability and an action.
Here only the records which the user can read will be returned. This is an Active Record scope so other scopes and pagination can be chained onto it.
Note: This does not work for abilities which were defined by a block because the conditions hash can not be determined from them. Instead an exception will be raised.
CanCan was inspired by declarative_authorization[http://github.com/stffn/declarative_authorization/] and aegis[http://github.com/makandra/aegis]. Many thanks to the authors and contributors.