3

I have a problem with 3 levels nesting of models in CanCan combined with Inherited Resources. I've read that we should nest everything up to 2 levels, but I had to put everything under account model and now I've tried doing this in CanCan:

load_and_authorize_resource :account
load_and_authorize_resource :project, :through => :account
load_and_authorize_resource :model, :through => :project

That gives me @account variable that has a value of @project, like it is overwriting that. @project is what is supposed to be and @model too. Is that fault of mine, CanCan's, Inherited Resources or just CanCan isn't supporting 3 levels nesting? Also, I do this in IR for the ModelsController.

belongs_to :account, :finder => :find_by_name! do
  belongs_to :project, :finder => :find_by_name!
end

Another strange thing is when i remove the part load_and_ from CanCan's definition. It works then, but I've read that it can be dangerous not to use the load part.

Can I use only the authorize_resource or should I do something with CanCan?

farnoy
  • 7,356
  • 2
  • 20
  • 30
  • 2
    I have no idea how many levels are supported through CanCan, but you can do you own loading and then call only the `authorize_resource` method instead. https://github.com/ryanb/cancan/wiki/Authorizing-Controller-Actions – jdl Mar 22 '11 at 18:02
  • You can use authorize_resource just make sure you use your before_filter for loading before the authorize_resource. – dombesz Mar 23 '11 at 11:39

1 Answers1

2

Your authorizations have been correct as far as I can say.

The developer of the CanCan gem ryan posted how this should behave: https://github.com/ryanb/cancan/issues/127#issuecomment-364475

That means that your

load_and_authorize_resource :account
load_and_authorize_resource :project, :through => :account
load_and_authorize_resource :model, :through => :project

will end up in an block like this (here: create action. For other actions should the last authorize! and the @model change):

@account = Account.find(params[:account_id])
authorize! :read, @account
@project = @account.projects.find(params[:project_id])
authorize! :read, @project
@model = @project.models.build
authorize! :new, @model

I hope that this answer can help developers looking for nested cancan authorization :-) .

source: https://github.com/ryanb/cancan/issues/127#issuecomment-364475


ps: wrong behavior for /accounts/1/projects/2/models/new:

load_and_authorize_resource :project
load_and_authorize_resource :model, :through => :project

This is kind of a security issue, because this will do

@project = Project.find(params[:project_id]) [...]

, and does not check if the current account is allowed to read the linked account '1'. And it does not check, if the project '2' is really a project of account '1'.

Adreamus
  • 670
  • 7
  • 15