1
votes

I recently integrated cancan (1.6.9) into my Rails (3.2.10) project for authorization, and I'm having an issue with manually loading a resource in a before_filter. Here's a brief description of my scenario.

In config/routes.rb, I have the following entries...

resources :users
match '/profile', :to => 'users#show'

Here's what my users_controller.rb looks like...

class UsersController < ApplicationController
  before_filter :load_show_resource, :only => :show
  load_and_authorize_resource
  ...
  def show
  end
  ...
  private

    def load_show_resource
      @user = params[:id] ? User.find(params[:id]) : current_user
    end
end

If my current_user's id is 1, this code will let me access localhost:3000/users/1 but not localhost:3000/profile.

The entry in my cancan ability.rb class that's blocking this access is seen below - it's the cannot section. If I comment out the cannot entry, both urls work.

...
can [:show, :update], User, :id => user.id
cannot [:show, :update, :destroy], User do |u|
  u.site_id != user.site_id
end
....

Shouldn't cancan use the resource that's being manually loaded in the before_filter for the show action regardless of whether or not params[:id] is present?

Interestingly enough, if I modify my users controller (see below) to use skip_load_and_authorize_resource :only => :show and manually calling authorize! in the show action, both urls work. Also, if I remove cancan altogether both urls work.

class UsersController < ApplicationController
  load_and_authorize_resource
  skip_load_and_authorize_resource :only => :show
  ...
  def show
    @user = params[:id] ? User.find(params[:id]) : current_user
authorize! :show, @user
  end
  ...
  private

    def load_show_resource
      @user = params[:id] ? User.find(params[:id]) : current_user
    end
end

So, my question is why does what's explained in the Override loading in the cancan documentation, not work in this situation?

Thanks!

1
What happens if you try to use the before_filter with the skip_load_and_authorize_resource workflow? - drewinglis

1 Answers

0
votes
# controller

class UsersController < ApplicationController
  load_and_authorize_resource, :except => :show
  # skip_load_and_authorize_resource :only => :show
  ...
  def show
    @user = params[:id] ? User.find(params[:id]) : current_user
    authorize! :show, @user
  end
  ...
end

# ability.rb

can [:show, :update, :destroy], User do |u|
  u.id == user.id && u.site_id == user.site_id
end