CanCan: load_and_authorize_resource in namespace other than that of MainApp
-
25-06-2021 - |
문제
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.
해결책
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)
다른 팁
CanCan can not find namespaced models. Try to specify class:
load_and_authorize_resource class: MyEngine::Form
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