-
Notifications
You must be signed in to change notification settings - Fork 0
Upgrading to 1.4
CanCan 1.4 is one of the largest updates yet. Here are the highlights, but check out the CHANGELOG for the full list.
A collection of resources is automatically loaded in the index
action using accessible_by
.
class ProductsController < ApplicationController
load_resource
def index
# @products automatically set to Product.accessible_by(current_ability)
end
end
Since this is a scope you can either ignore it or build on it further.
def index
@products = @products.paginate(:page => params[:page])
end
The @products
variable will not be set if Product
does not respond to accessible_by
(for example if you aren't using Active Record). It will also not be set if you are using blocks in any of the can definitions because that is incompatible with accessible_by
.
There are many backward-incompatible changes regarding blocks in can
definitions.
The block is no longer triggered if a class is passed in to the can?
check. This makes the behavior consistent with the conditions hash and means you no longer need to check for nil.
can :read, Project do |project|
project.in_group? :foo
end
can? :read, Project # returns true without triggering block
can? :read, @project # triggers block
The action and class are no longer passed to the block when using :manage
or :all
arguments. Only the object is passed in. Here are a couple examples:
can :manage, :Project do |project|
# ...
end
can :manage, :all do |object|
# ...
end
If you need the old behavior (like when defining Abilities in Database), you can call can
without any arguments and everything will be passed to the block. This block will also be triggered with every check no matter if only a class is passed in to the can?
check.
can do |action, subject_class, subject|
# ...
end
The AccessDenied messages can be customized through internationalization. For example:
# in locales/en.yml
en:
unauthorized:
manage:
all: "Not authorized to %{action} %{subject}."
user: "Not allowed to manage other user accounts."
update:
project: "Not allowed to update this project."
Notice manage
and all
can be used to generalize the subject and actions. Also %{action}
and %{subject}
can be used as variables in the message.
If you want air-tight authorization to be certain you don't forget it in some controller action, add check_authorization
to your ApplicationController
or any other controller.
class ApplicationController < ActionController::Base
check_authorization
end
This will add an after_filter
to ensure authorization takes place in every inherited controller action. If not it will raise an exception. You can skip this check by adding skip_authorization
to that controller. Both of these methods take the same arguments as before_filter
so you can exclude certain actions.
TODO
It will automatically detect if you are using Inherited Resources and load the resource through that. The load_resource
call is still necessary however to support additional loading such as in the index
action.
class ProjectsController < InheritedResources::Base
load_and_authorize_resource
end
If you want to contribute to this project, a Gemfile
has been added to make it easy to start developing and running the specs. Just run bundle
and rake
to run the specs. This currently does not work in Ruby 1.9.