-
Notifications
You must be signed in to change notification settings - Fork 783
Upgrading to 1.1
CanCan version 1.1 includes several features along with a few backwards incompatible changes.
Abilities can now be restricted using a conditions hash instead of a Ruby block. For example, if you previously had this.
can :update, Article do |article| article && article.user == user && article.visible? end
You can now do this.
can :update, Article, :visible => true, :user_id => user.id
The block is still available but I encourage you to use condition hashes whenever possible because it can be used in database queries.
See Defining Abilities with Hashes for more information.
One of the biggest limitations of CanCan in the past was that it was not possible to use the Ability logic in a database query to fetch only the readable records. With the addition of condition hashes to define abilities it is now possible to use that in the database through the added accessible_by
scope in Active Record.
# in controller @articles = Article.accessible_by(current_ability)
This will only fetch the articles which the current user has read access to. If you are not using Active Record you can access the conditions hash directly.
current_ability.conditions(:read, Article)
See Fetching Records for more information.
If you are testing the Ability class through RSpec there is a new be_able_to
matcher available. This checks if the can?
method returns true.
require "cancan/matchers" # ... ability.should be_able_to(:read, Article)
Also see Testing Abilities.
It is now possible to pass additional arguments to the can?
method. These will be passed into the block. This is useful for passing additional information about the request.
# in controller or view can? :read, article, request.remote_ip # in ability can :read, Article do |article, remote_ip| # ... end
See Accessing Request Data for an alternative solution.
You can now access additional information about the unauthorized action inside the CanCan::AccessDenied
exception. This is useful for changing the behavior in the rescue_from
clause.
exception.action # => :read exception.subject # => Article
You can also change the default error message from here. This will be returned as the message if one wasn’t specified when the exception was raised.
exception.default_message = "Unauthorized!" exception.message # => "Unauthorized!
See Exception Handling for more information.
An authorize!
method was added to the controller. Instead of this.
unauthorized! if cannot? :read, @article
Do this.
authorize! :read, @article
This performs the can?
check and raises the exception if needed. You can pass a custom message with the :message
option.
authorize! :read, @article, :message => "Not authorized to read this article."
The unauthorized!
method has been removed. Use authorize!
instead as shown above. If you need more custom behavior you can raise the exception manually.
raise CanCan::AccessDenied.new("Cannot read article.", :read, @article)
If you used the :class
option in the load_and_authorize_resource methods then use :resource
instead. This change allows for a symbol to be passed into :resource
if there is no class to use.
If you defined the current_ability
method in the controller you’ll now need to cache it like so.
def current_ability @current_ability ||= CustomAbility.new(current_account) end
This project is abandoned, see its successor: CanCanCan