Qaiser Wali
Qaiser Wali

Reputation: 358

Rails 3 CanCan nested Resources

Have a nested resource as such

class Dealer < ActiveRecord::Base
  has_many  :vehicles
end

and

class Vehicle < ActiveRecord::Base
  belongs_to :dealer
end

below are my routes.

  resources :dealers do
    resources :vehicles,           :except => [:index]
  end
  resources :vehicles, :only => [:index]

looking at the wiki at the github page for cancan I did the following:

class VehiclesController < ApplicationController
  load_and_authorize_resource :dealer
  load_and_authorize_resource :vehicle, :through => :dealer

  def index
    @vehicles = Vehicle.all

    respond_to do |format|
      format.html # index.html.erb
      format.json { render json: @vehicles }
    end
  end
end

but now when the admin tries to go to the index page with the abilities:

def initialize(user)
  user ||= User.new # guest user (not logged in)
  if user.has_role? :admin
    can     :manage, :all
  end
end

I get

Couldn't find Dealer with id=

what do i need to change for admin to still be able to do all the actions and yet have others be checked before they can do any action.

Upvotes: 0

Views: 310

Answers (2)

dre-hh
dre-hh

Reputation: 8044

The problem is not that he is not authorized to this action. The problem is that CanCan tries to fetch an instance of dealer to load all its vehicles and you have not provided a :dealer_id within params[:dealer_id]. Cancan assumes you would be loading only dealer's vehicles in this controller because you used an load_and_authorieze :through. This authorization should be used within Dealers::VehiclesController.

As long as you only loading vehicles just use load_and_authorize_resource :vehicle. And because load_and_authorize will set @vehicles for you within the before filter there is also no need to load the vehicles explicitly with Vehicle.all.

load_and_authorize is just a convenient method and it assumes some defaults. Once you will come to a point where you have some more complex use case. It will be time to throw away this method and just use CanCan's authorize!, can? and a properly configured Vehicle .accessible_by (for listing) methods.

Upvotes: 1

nbon
nbon

Reputation: 2805

When using load_and_authorize_resource :vehicle, through: :dealer it expects to receive a dealer_id in the request in order to authorize the dealer.

Since you use except: :index in your routes dealer_id will not be automatically included in the request.

If you don't want to authorize the dealer in the index action you can do something like this (taken from Can Can wiki)

class CommentsController < ApplicationController
  load_and_authorize_resource :post
  load_and_authorize_resource :through => :post

  skip_authorize_resource :only => :show  
  skip_authorize_resource :post, :only => :show
end

Upvotes: 0

Related Questions