An intro to CanCan and managing permissions, authorization

Written by on

CanCan is our goto library for managing permissions in our applications. Like any library, you have to know how to use it. It comes with its own set of nuances and patterns. If you don't properly organize and manage it, you'll end up with a load of technical debt.

Before getting into details, you should understand a few key details about CanCan. These are details we've run into many times before and it always seems to trip up new people using the CanCan library. 

  1. check_authorization  If you're using CanCan, you'll want to be sure you are checking authorization. This happens in your controllers. Most of the time, it should be an exception if you skip authorization. Why would you define a bunch of permissions and then forget to authorize against them?
  2. load_and_authorize_resource:  Based on the permissions you've defined in your abilities file, CanCan can load and authorize your models in your controllers. For example, if you have a PostsController and you use the index action, CanCan will load all @posts which a user has access to. There are exceptions and loading your index action will fail if you use a block to define permissions.
  3. Ability precedence:  This is one of the most important gotchas and you may lose some time trying to debug this. Make sure you read about ability precedence and experiment with it. It's important to note that with CanCan, manage means any. If you can manage a post, you can perform any action on that post. The first permission you define takes precedent over any that follow.

Here's a block of code to help you understand the points above: 

With the introduction of strong_parameters in Rails 4 (also a great pattern you can use in your Rails 3 projects), you'll want to have a pattern for using it in unison with CanCan. CanCan doesn't natively support strong_parameters yet. CanCan attempts to load params before being filtered by strong_parameters; thus, strong_parameters raises an exception.

For us, we've started to use cancan_strong_parameters  which patches CanCan to allow strong_parameters. We'll try to update this post when CanCan begins to support strong_parameters.

How do you handle strong_parameters with CanCan? Let us know in the comments below.