Having using Acl9 for some time, it was refreshing to see RailsCast’s Ryan Bate’s take on authorization: CanCan. Ryan put together a webcast for CanCan that you can checkout here. There have been some nice additons since this initial release so do checkout the latest documentation on GitHub. I won’t go into what I dislike about Acl9. It’s a good system, with a nice DSL for defining permissions. I’ll just talk about some of the things I’ve enjoyed about CanCan. If you haven’t explored the library, you should.
Lightweight
There is very little setup involved. In fact, nothing by default is kept in the database. You decide how permissions are assigned. It can be as simple as a flag on a user on up to a complex role based setup. For example, let’s say my system had some fairly unsophisticated requirements. You’re either an admin, or you’re a normal everyday user. Slap an admin flag on the user model, and be on your way. Typically, permissions are defined inside a model named Ability.
class Ability
include CanCan::Ability
def initialize(user)
if user.admin?
can :create, User
end
end
endIndex authorization
This is a big one. Since CanCan 1.1, we’ve been able to define abilities that can be used for lookups. It’s one thing to determine if we do or do not have permissions on an object that we’ve already been handed. It’s another animal entirely to be able to retrieve the records that a particular user has permissions to. CanCan makes this dead simple. We just need to add a conditions hash when defining the ability.
can :read, Widget, :user_id => user.id, :active => trueNow all we need to do in our controller to retrieve only what our user should have access to read:
@widgets = Widgets.accessible_by(current_ability)How awesome is that??!? AND it’s an Active Record scope, so we can chain other scopes onto it!
Easy controller integration
Ryan’s provided a nice method (load_and_authorize_resource) we can call inside of our controllers to both load and authorize the resource for the requested action.
class WidgetsController < ApplicationController
load_and_authorize_resource
def show
# We've already retrieved @widget and
# authorized the current user for the show action!
end
endThis will work for all 7 restful actions. If you need to do something fancy with your model prior to the load_and_authorize call, you can use a before filter. It will play nice and skip the load portion if it sees that you’ve already taken care of business.
There’s a good deal more to CanCan, this is just a little taste. Hopefully it’s been enough to wet your whistle and go explore a little further.

