All rules are evaluated on every request #700

jackquack opened this Issue Jul 25, 2012 · 6 comments

3 participants


I have a large set of rules for my models that follow a similar pattern

can :manage, Project, :group => { :id => user.group_ids }
can :manage, Posts :team => { :id => user.team_ids }
# obvious it's much much longer and much more complex in reality

However, every request, for every resource, evaluates every line of my ability file. So, in my log file, I see SQL queries for a user's team, for every single line that I use something like user.team_ids. Every ability statement is evaluated no matter which resource is currently being requested.

So, for example, when a user requests /posts.json, every statement outlining permissions for all sorts of resources in my ability.rb file is fully evaluated.

SELECT `id` FROM `group` where = 1;

Is this normal?


I'm new to cancan but as far as I can tell, yes, that is normal. Essentially the group_ids and team_ids return an array which is then fed into cancan. Since you're able to define abilities based on the actual instance of the user, cancan must read the ability file each time you check authorization. Even though cancan realizes the ability doesn't apply, in defining the ability, you've already fetched the team_ids to define the ability.

You could do it with blocks, but you will only be able to check per-instance rules within the block. Therefore you would be able to prevent the user from entering a project they were not a part of, but not exclude those projects from a listing of all projects this user can see.

I agree with you, it would be nice to pass a block that would be executed only if the ability could possibly apply. e.g. in cancan 2.0 notation

can :access, :projects {|user| :group => {:id => user.group_ids } }

This would only execute the block if we were checking project abilities.


So, it seems like the best solution is to use blocks, and then manage index permissions myself, until 2.0 arrives.

Yes, it definitely seems like I NEED 2.0 to be able to declare these permissions with any sort of sanity.

That can :access, :projects notation looks pretty promising. The example I gave is just the tip of the iceberg in terms of what I'm dealing with. For instance, projects have things like Documents. So, to access the index of documents which belong to the project (foreign key), the user must be a group member of the project (many to many). So anyway, it gets hairy quickly.

I WAS doing everything through blocks before I realized that they don't work for indexes.


Well, don't get me wrong, the code I posted was just a possible notation, not actually how it works. As I understand it, cancan 2 works the same way for blocks, but allows you to write a lot of your cancan 1 blocks as inline statements instead. Maybe there's someone out there who needs it bad enough to make a patch and pull request it.

Luckily I currently only need to check the on all my abilities ;)


You might find it easier to think of abilities a little differently. In the case of your Documents controller, you're listing all documents that are part of the project the user is in. Why not just do the following (I'm writing using cancan 2.0, not sure what is available in 1.x):

class DocumentsController < ApplicationController
   def index
      project = Project.find(params[:project_id])
      authorize! :read, project
      @documents = project.documents

Now you don't need to look up anything in the ability file related to documents, because viewing documents only depends on whether or not you can read the project.


Hi @jackquack

If you feel your question has now been answered, would you mind closing this issue, please?

Otherwise, please add a further comment with any outstanding issues.


I guess my question was 'Is this normal?' and the answer is 'yes'. So, in that sense, it is answer. And I've given my 2 cents on to his this probably should be improved 'lazy evaluation'. So, I'll close. :)

@jackquack jackquack closed this Mar 13, 2013
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment