Skip to content

Latest commit

 

History

History
60 lines (42 loc) · 2.1 KB

define_abilities_with_blocks.md

File metadata and controls

60 lines (42 loc) · 2.1 KB

Define abilities with blocks

If your conditions are too complex to define in a hash of conditions, you can use a block to define them in Ruby.

can :update, Project do |project|
  project.priority < 3
end

Note that if you pass a block to a can or cannot, the block only executes if an instance of a class is passed to can? or cannot? calls.

If you define a can or cannot with a block and an object is not passed, the check will pass.

can :update, Project do |project|
  false
end
can? :update, Project # returns true!

Fetching Records

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:

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.

Block Conditions with ActiveRecord Scopes

It's also 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 of caveats:

  • You cannot use this with multiple can definitions 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.