Restricted by default #191

ryanb opened this Issue Nov 9, 2010 · 8 comments


None yet

3 participants

ryanb commented Nov 9, 2010

There are a couple of things that I appreciate about the Lockdown project which I feel CanCan lacks.

  1. Everything is locked down by default.
  2. It is not specific to RESTful controllers.

While it's possible to mimic this behavior with Ensure Authorization and use CanCan in Non RESTful Controllers. I would like this behavior to be simpler and intuitive.

What if there is a controller class method for enabling authorization. This will usually be done in the ApplicationController so everything is restricted.

class ApplicationController < ActionController::Base

This would add a before_filter to every action which checks the permission on Ability. The default behavior would simply pass in the controller action name as the verb and the controller name as the noun.

can :create, :projects

This makes Non RESTful controllers just as easy to limit. For example, if there's a HomeController#index action we could do.

can :index, :home

The action aliases are still set up so one can use :read or :manage instead of :index there.

The problem is how will this fit in with handling conditions based on model attributes. Also, because this changes the focus to controller actions it makes setting permissions on individual attributes (see #154) less obvious.

Just throwing this idea out there, let me know what you think!

ryanb commented Mar 16, 2011

I will be moving forward with what's mentioned in this issue for the 2.0 release.

I will also be changing :manage to :access because it's more generic and fits other non restful controllers.

can :access, :home # can access any action on home controller

Checking on model instances will match based on the pluralized class name.

can :read, :projects, :discontinued => false
can? :read, => false) # will return true
can? :read, :projects # will return true like normal

Using a class directly will be deprecated. For cases where the subject name can't be inferred there will be support for subject aliases which work much like action aliases. There will be the ability to pass a class name and alias it to a subject name.

alias_subject User, :to => :authors
can :read, :authors
can? :read, # returns true

Since authorization will be enabled by default in all controllers. The load_and_authorize_resource call will be deprecated and only load_resource will be needed. One can call skip_authorization on any controller where they don't want authorization to take place. This works for restful and non restful controllers.


Setting permissions for individual attributes will also be supported as mentioned in issue #154.

can :update, :projects, [:name, :priority]
can? :update, @project, :name # returns true

This removes the need for attr_accessible in models since each attribute will be checked automatically with authorization if you're using load_resource.

This also makes it easier to add conditions for parent resources when nesting is involved. The association can be treated as an attribute:

can :access, :projects, :categories

These are all some ideas on where I see CanCan 2.0 going. What do you think?

rbritom commented Mar 16, 2011

is it posible to add a method that prints the resulting permissions for a given resource? it would be so helpful during development.

ryanb commented Mar 16, 2011

Good idea. I hope to improve debugging in 2.0 including a way to enable logging which will state all the permissions it goes through, etc.

clyfe commented Mar 19, 2011

How is the attributes default to be handled?

 can :update, :projects # allow to all attributes
 can :update, :projects, [:name, :priority] # allow only these two attributes

I think :only and :except semantics are a good candidate here

 can :read, :user, :only => [:email]
clyfe commented Mar 19, 2011

Also "authorization will be enabled by default in all controllers" should allow opt-out.

ryanb commented Mar 20, 2011

@clyfe, thanks for the suggestion. I haven't thought through all the possibilities of the 3rd parameter yet. I will need to do some experimenting. The problem with allowing an only/except hash of options is that it conflicts with the use of a hash of conditions.

I think we can make more use of the cannot call. If you want to do all attributes except one or two, do this.

can :update, :products # allow all attributes
cannot :update, :products, :price

I will also consider adding an option for the 3rd parameter to always be required. This way one needs to always be explicit on the attributes and use :all to represent all.

can :update, :products, :all

If one is using this in place of attr_accessible I think this is a good solution to ensure they don't forget it anywhere.

ryanb commented Mar 20, 2011

Regarding your second suggestion, the enable_authorization method will accept :if and :unless options to disable it dynamically. I thought about adding a skip_authorization method one can call, but separating authorization from loading gets complicated in load_and_authorize_resource. CanCan 1 attempts to do this but I don't think it does a very good job.

If you want to "skip" authorization in a controller, it's just as easy to allow access to it in the Ability class, so I'm not certain it's entirely necessary. This is something I will have to wait until I get some implementation to test it.

ryanb commented Mar 26, 2011

The majority of what I mentioned here is now implemented in the 2.0 branch. Closing this. Open up a separate issue if you find specific problems.

@ryanb ryanb closed this Mar 26, 2011
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment