CanCan: load_and_authorize_resource in namespace other than that of MainApp
Asked Answered
S

3

6

I'm using CanCan for permissions in my Rails application in which I have built my own engine for some generic form functionality. I would like to lock down permissions in my system so that users cannot freely access my engine controllers' actions. These controllers, for the most part, just make use of the 7 REST actions, so I would like to use CanCan's load_and_authorize_resource at the top of each controller.

However, when I write my code like this:

    module MyEngine
      class FormController < ApplicationController
        load_and_authorize_resource
        ...
      end
    end

I get this error:

    uninitialized constant Form

My guess is that the automatic loader in load_and_authorize_resource is tied to my MainApp namespace, and does not recognize that I am calling it in a different namespace, and so does a call like Form.find(params[:id]) rather than MyEngine::Form.find(params[:id]).

If this is the case, how can I fix this? It's not a huge deal because authorize! still works properly, so I can define the authorization in each action individually, but it would feel much cleaner if I were able to use the load_and_authorize_resource method.

Secede answered 12/8, 2012 at 20:1 Comment(1)
possible duplicate of Authorizing Namespaced and Nested controllers using CanCanJardiniere
B
6

It seems to be a bug in CanCan::ControllerResource#namespace:

def namespace
  @params[:controller].split("::")[0..-2]
end

As you see, it tries to split controller path by :: but it comes in the form of my_engine/my_controller.

So the fix is dumb simple:

def namespace
  @params[:controller].split("/")[0..-2]
end

Wonder how they could miss such a stupid bug for so long. Shall send them a pull request.

P.S. Have just signed up to answer 8)

Blabbermouth answered 1/3, 2013 at 20:25 Comment(3)
Oh! It's even more interesting: they seem to just forget merging the fix to master branch. github.com/ryanb/cancan/issues/663Blabbermouth
Nice one, this was just what I needed!Plutocracy
A patch for this was applied in 1.6.10Jardiniere
L
9

CanCan can not find namespaced models. Try to specify class:

load_and_authorize_resource class: MyEngine::Form
Leyden answered 21/8, 2012 at 17:14 Comment(0)
B
6

It seems to be a bug in CanCan::ControllerResource#namespace:

def namespace
  @params[:controller].split("::")[0..-2]
end

As you see, it tries to split controller path by :: but it comes in the form of my_engine/my_controller.

So the fix is dumb simple:

def namespace
  @params[:controller].split("/")[0..-2]
end

Wonder how they could miss such a stupid bug for so long. Shall send them a pull request.

P.S. Have just signed up to answer 8)

Blabbermouth answered 1/3, 2013 at 20:25 Comment(3)
Oh! It's even more interesting: they seem to just forget merging the fix to master branch. github.com/ryanb/cancan/issues/663Blabbermouth
Nice one, this was just what I needed!Plutocracy
A patch for this was applied in 1.6.10Jardiniere
G
3

If the model class is namespaced differently than the controller, you will need to specify the :class option.

module MyEngine
  class FormController < ApplicationController
    load_and_authorize_resource :class => MyEngine::Form
    ...
  end
end
Goodwill answered 22/8, 2012 at 8:32 Comment(1)
I'm getting uninitialized constant MyEngine::Form for this.Pitzer

© 2022 - 2024 — McMap. All rights reserved.