Search code examples
ruby-on-railsrubyauthorizationcancanrole-base-authorization

CanCan authorization issue index action


I am having an issue trying to use the cancan authorization. I have users with one role per user, so I added user.role column as suggested in the cancan wiki.

I also have an index view for kindergardens and another index view for children.

What I am trying to achieve is to only allow access to the index views to the corresponding users with role kindergarden or parent (for children).

When I now authorize Kindergardens in kindergardens controller nobody is allowed to access the index view, although I defined it in my ability model.

Help would be much appreciated. I have no idea what I am missing...

Ability model:

class Ability
include CanCan::Ability

def initialize(user)
[...]
elsif user.role == 'kindergarden'
   can [:update, :destroy], Kiga do |kiga|
     kiga.user_id == user.id
   end
   can :read, Kiga do |kiga|
     kiga.user_id == user.id
   end
   can :index, Kiga

   can :create, Kiga
else

end

Kindergardens controller:

class KigasController < ApplicationController
before_action :set_kiga, only: [:show, :edit, :update, :destroy]

# GET /kigas
# GET /kigas.json
def index
  @kigas = Kiga.all
  authorize! :index, @kiga
end

Solution

  • You define your abilities as blocks and that needs to have instances. In index actions you have only Active Record scopes, not actual instances.

    Btw you have a typo in controller code:

    def index
      @kigas = Kiga.all
      authorize! :index, @kigas # was @kiga that is nil probably
    end
    

    See the docs:

    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).

    In this case you can use hashes of conditions

     can [:update, :destroy], Kiga, user_id: user.id