HTTPS clone URL
Subversion checkout URL
Defining Abilities with Blocks
- 3rd party add ons
- Abilities in Database
- Ability for Other Users
- Ability Precedence
- Accessing request data
- Action Aliases
- Admin Namespace
- Authorization for Namespaced Controllers
- Authorization in Web Services
- Authorizing controller actions
- CanCan 2.0
- CanCan 2.0 Aliases
- Changing Defaults
- Checking Abilities
- Controller Authorization Example
- Custom Ability Methods
- Custom Actions
- Debugging Abilities
- Defining Abilities
- Defining Abilities with Blocks
- Defining Abilities with Hashes
- Ensure Authorization
- Exception Handling
- Fetching Records
- Inherited Resources
- Issue Collaborators
- Link Helpers
- Model Adapter
- Multiple can definitions (from 1.3)
- mvc deficiencies
- Nested Resources
- Non RESTful Controllers
- Other Authorization Solutions
- Rails API Gem
- Role Based Authorization
- Separate Role Model
- Separating Abilities
- Share Ability Definitions
- Testing Abilities
- Translating your app
- Upgrading to 1.1
- Upgrading to 1.3
- Upgrading to 1.4
- Upgrading to 1.5
- Upgrading to 1.6
Clone this wiki locally
If your conditions are too complex to define in a hash (as shown in Defining Abilities page), you can use a block to define them in Ruby.
can :update, Project do |project| project.priority < 3 end
If the block returns true then the user has that ability, otherwise they will be denied access.
The block is only evaluated when an actual instance object is present. It is not evaluated when checking permissions on the class (such as in the index action). This means any conditions which are not dependent on the object attributes should be moved outside of the block.
# don't do this can :update, Project do |project| user.admin? # this won't always get called end # do this can :update, Project if user.admin?
See Checking Abilities for more information.
A block's conditions are only executable through Ruby. If you are Fetching Records using
accessible_by it will raise an exception. To fetch records from the database you need to supply an SQL string representing the condition. The SQL will go in the
WHERE clause, if you need to do joins consider using sub-queries or scopes (below).
can :update, Project, ["priority < ?", 3] do |project| project.priority < 3 end
If you are using
load_resource and don't supply this SQL argument, the instance variable will not be set for the index action since they cannot be translated to a database query.
As of CanCan 1.6 it's possible to pass a scope instead of an SQL string when using a block in an ability.
can :read, Article, Article.published do |article| article.published_at <= Time.now end
This is really useful if you have complex conditions which require
joins. A couple caveats:
- You cannot use this with multiple
candefinitions that match the same action and model since it is not possible to combine them. An exception will be raised when that is the case.
- If you use this with
cannot, the scope needs to be the inverse since it's passed directly through. For example, if you don't want someone to read discontinued products the scope will need to fetch non discontinued ones:
cannot :read, Product, Product.where(:discontinued => false) do |product| product.discontinued? end
It is only recommended to use scopes if a situation is too complex for a hash condition.
You can override all
can behavior by passing no arguments, this is useful when permissions are defined outside of ruby such as when defining Abilities in Database.
can do |action, subject_class, subject| # ... end
Here the block will be triggered for every
can? check, even when only a class is used in the check.