TL;DR overwrite as_json on all your CanCan Ability classes.

Since I’ve started using squash for bug tracking I started noticing exceptions which prevented squash client from transmitting exceptions to the squash backend.

The exceptions squash was rescueing made squash raise a new exception!

Digging through the stack traces it became obvious that Ryan Bates cancan is the root of all evil.

To reproduce fire up irb and paste the following lines:

# dependencies to reproduce
require 'cancan'         # v1.6.10
require 'json'           # v1.7.7
require 'active_support' # v3.2.12
require 'active_record'
require 'sqlite3'        # v1.3.7

# we need active record
  :adapter => "sqlite3",
  :database  => ":memory:"

# and two sample classes
class User < ActiveRecord::Base

ActiveRecord::Migration.create_table :users do |t|

class Project < ActiveRecord::Base
  belongs_to :user

ActiveRecord::Migration.create_table :projects do |t|
  t.belongs_to :user

# as well as an Ability
class Ability
  include CanCan::Ability

  def initialize user

    can [:new, :create, :edit, :update, :destroy], Project do |project|
      project.user == user

ability =
ActiveSupport::JSON.encode(ability) # => boom

You’ll see an ActiveSupport::JSON::Encoding::CircularReferenceError: object references itself exception.

As far as I can tell this is due to the data structure CanCan is using to store the permissions.

Defining as_json as follows solves this problem:

def as_json *args
  return {
    class_name: 'Ability',
    user_id: null # your metadata here

I’d vote to make this a default in CanCan, but for the time being this solves my problem while still leaving enough debugging informations for me to reproduce error states.

That being said, I really like cancan - it’s a great gem. But those circular reference errors are something to watch out for.

comments powered by Disqus