Search code examples
deviseauthorizationcancan

Cancan ability not restricting access to associated user


Rails 3.2; Ruby 2.1; Cancan 1.6.10; User is a devise model.

I've followed the instructions for restricting controller actions based on attributes and have setup the following ability.rb file:

class Ability
  include CanCan::Ability

  def initialize(user, params)
    if user
      if user.admin?
        can :manage, :all
      elsif user.employee?
        cannot :manage, User

        # Works
        # can :manage, User if params[:id].to_f == user.id.to_f

        # Doesn't work
        can :manage, User, id: user.id
      else
        cannot :manage, :all
      end
    end
  end
end

I can not get the line: can :manage, User, id: user.id to work. It still allows me to edit any User with a path like /users/4/edit even though that is not the id of the user. However, if I use the line above with the if statement, it works properly.

I've also tried passing in a block like:

can :manage, User, do |usr|
  Rails.logger.debug("usr.id: #{usr.id}")
  usr.id == user.id
end

Which doesn't even print to the log. Been at this for hours and am not really sure what the problem is.

UPDATE

I went though CanCan debugging and am getting conflicting results. Using the line can :manage, User, id: user.id; I get the following results in console:

admin = User.find(1)#role of "admin"
user = User.find(4) #role of "employee"

ability = Ability.new(user)
ability.can?(:edit, user)
# true
ability.can?(:edit, admin)
# false

ability = Ability.new(admin)
ability.can?(:edit, user)
# true
ability.can?(:edit, admin)
# true

However, I'm still able to navigate to and edit (with changes being saved) other users while I'm logged in as user 4

Additionally, it works properly if I add the following to the controller:

def edit
  @user = User.find(params[:id])

  unless can? :edit, @user
    redirect_to dashboard_path, alert: 'You do not have sufficient privileges to edit other users.'
  end
end

I was under the impression that this shouldn't be necessary given what I have in ability.rb


Solution

  • So the problem ended up being that in the controller I was using authorize_resource instead of load_and_authorize_resource. Once I switched it to the later I was able to define abilities in ability.rb.