Demo of how to use cancan-permits in a Rails 3 app
Ruby JavaScript
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Failed to load latest commit information.


Rails 3 demo app for using CanCan permits

Uses version 0.3.1 of cancan-permits.

Create Model

  • Create User model with a :role attribute
  • Create Article model
  • Let a User have many Articles

User model

$ rails g scaffold user name:string role:string

class Article < ActiveRecord::Base belongs_to :user end

Article model

$ rails g scaffold article user_id:integer name:string body:string

class User < ActiveRecord::Base has_many :articles end

Create Permits (and Licenses) using the generator

$ rails g permits --roles editor

create app/permits/guest_permit.rb create app/permits/admin_permit.rb create app/permits/editor_permit.rb create app/permits/any_permit.rb create app/permits/system_permit.rb

 create  app/licenses/user_admin_license.rb  
 create  app/licenses/blogging_license.rb  

To avoid generating deault licenses: $ rails g permits --roles editor --no-default-licenses

To get list of all generator options $ rails g permits

Edit permits

Admin permit: def permit?(user, options = {}) return if !role_match? user
can :manage, :all

Any permit: def permit?(user, options = {}) super

Editor permit: def permit?(user, options = {}) super return if !role_match? user
owns(user, Article) end

Guest permit: def permit?(user, options = {}) super
return if !role_match? user
can :create, Article end

System permit: def permit?(user, options = {}) super request = options[:request] if request && && localhost_manager? can(:manage, :all) return :break end

The system permit illustrates an example of how custom data can be sent into the options hash to be used for considering whether to give permission. Here it is assumed that the :request key can optionally have a request object to be used to determine if the user is accessing the app from localhost.

Test that it works!

Migrate the DB (Development mode)

$ rake db:migrate

Seed the database with initial data (optional)

rake db:seed

Make the Test DB reflect the evelopment DB

rake db:test:prepare

The main spec is in spec/models/user_spec.rb

$ rspec models/user_spec.rb

Integrating CanCan REST links

Gemfile gem 'cancan', '~> 1.4.0' # not sure this one is needed, but ...
gem 'cancan-rest-links', '~> 0.1.6' gem 'cream', '~> 0.7.4'
gem 'devise', '~> 1.2.0'

Run bundler $ bundle install

$ rails generate devise:install

$ rails generate devise User

Fix the devise user migration:

class DeviseCreateUsers < ActiveRecord::Migration def self.up drop_table :users # <----- temporary hack, remove after migration is run

  create_table(:users) do |t|
    t.string :name    # <-----
    t.string :role    # <----- 

    t.database_authenticatable :null => false  


Update the Database!

$ rake db:migrate

rake db:test:prepare

Create a Rails initializer 'initializers/rest_links.rb'

We need to define the available roles in a central location.

module Cream def self.available_roles [:guest, :admin, :editor] end end

We should also modify the User model in 'models/user.rb' to reference this and add a #has_role? method

class User def self.roles Cream.available_roles # [:guest, :admin, :editor] end

def has_role? role (self.role || 'guest').to_sym == role.to_sym end

Setup a Devise user authentication filter

Make all pages require login

application_controller.rb class ApplicationController < ActionController::Base protect_from_forgery
before_filter :authenticate_user!

This will ensure that current_user is set, which is fx used by CanCan's #can? and #cannot? methods

Modify Devise views

Now we need to configure the sign up form:

$ rails generate devise:views

in 'views/devise/registrations/new.html.erb'

We insert some code to create a text field to enter the role of a user

<%= f.label :role %>
<%= f.text_field :role %>

Test the full Authorization system with users and Permits

$ rails server

Now when we go to localhost:3000/articles, we will be sent to a page asking us to login or signup. If we signup we can create a user and experiment with different roles, then edit the permission files and see which links will be active or not for a given user with a given role. Nice!


In order to contribute to and improve the framework, I suggest you start by cloning the gems used:

$ git clone git:// $ git clone git:// $ git clone git://

Then configure the Gemfile to point to your local gem copy

Gemfile gem 'cancan-permits', '~> 0.3.1', :path => '/...//cancan-permits' gem 'cancan-rest-links', '~> 0.1.6', :path => '...//cancan-rest-links' gem 'cream', '~> 0.7.4', :path => '/...//cancan-permits'

Then you are free to put whatever debugging code (p puts and ... statetement?) in your local copy of the gems.


If you have problem with the rspec executable version, reinstall any rspec > 2.0.1 and try again.

$ gem list rspec $ gem install rspec -v 2.1.0