Upgrading to 1.1
Clone this wiki locally
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.
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
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.
authorize! method was added to the controller. Instead of this.
unauthorized! if cannot? :read, @article
authorize! :read, @article
This performs the
can? check and raises the exception if needed. You can pass a custom message with the
authorize! :read, @article, :message => "Not authorized to read this article."
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