Namespaced policy and controller can't find authorization target for index
Tell us about your environment
Ruby Version: 3.0.1
Framework Version (Rails, whatever): Rails 6.1.3.1
Action Policy Version: 0.5.7
What did you do?
I created a controller and namespaced policy very similar to the example of nested modules in the docs.
My controller (simplified)
class Admin::Client::ReportsController < ApplicationController
def index
authorize!
@reports = Report.all
end
def show
@report = Report.find(params[:id])
authorize! @report
end
end
My policy
class Admin::Client::ReportPolicy < ApplicationPolicy
def index?
user&.admin?
end
def show?
user&.admin?
end
end
What did you expect to happen?
When calling either index or show, I expect the corresponding policy to be called.
What actually happened?
When calling show, the policy is found and correctly called. When calling index, i get the following error
ActionPolicy::NotFound (Couldn't find policy class for [#<Admin::Client::ReportsController:0x0000000004a8d0>, "Couldn't find implicit authorization target for Admin::Client::ReportsController. Please, provide policy class explicitly using `with` option or define the `implicit_authorization_target` method."] (Array)):
Any help? Since nested namespaces with an index action are mention explicitly in the docs, I thought that I should need to explicitly provde the authorization target
I recently upgraded my rails version to 6.1.3.2 and I have started getting similar error:
Couldn't find policy class for #<GraphQL::Pagination::ActiveRecordRelationConnection:0x00007f8b55e74a18 @items=#<ActiveRecord::Relation [#<Brand id: 2, created_at: "2020-02-26 08:46:09.450541000 +1100", updated_at: "2021-02-08 11:19:24.364907000 +1100", name: "Adidas", description: "desc....">]>, @parent=nil, @context=#<Query::Context ...>, @field=#<Types::BaseField Query.brands(...): BrandConnection!>, @first_value=10, @after_value=nil, @last_value=nil, @before_value=nil, @arguments={:first=>10}, @edge_class=GraphQL::Pagination::Connection::Edge, @has_max_page_size_override=true, @max_page_size=100> (GraphQL::Pagination::ActiveRecordRelationConnection)
I'm using action_policy and action_policy-graphql gems.
Hey @ingnam!
That looks like a different problem: GraphQL::Pagination::ActiveRecordRelationConnection instance is passed as the record, which we don't know how to resolve. Likely, related to some GraphQL-ruby changes or other GraphQL gems.
Could you please open a separate issue in https://github.com/palkan/action_policy-graphql ?
@robbevp The problem is that controller_name.classify.safe_constantize returns nil for some reason (though we definitely have the Report class).
What if you add Report as an argument?
authorize! Report
(What surprises me more is that an array with exception message is passed as implicit target ð€ it should raise an exception (unless #raise is overriden))
@robbevp Could you please take a look at the question above?
Hi @palkan Sorry for my late response.
If I add the class as an argument, everything works as expected.
Hm, interesting; could you share the results of the following expression (executed right before authorize!):
Ñontroller_namecontroller_name.classifycontroller_name.classify.constantize
The constantize seems to be the source of the problem:
Ñontroller_name: reports
Ñontroller_name.classify: Report
But constantizing throws uninitialized constant Report since my model is also namespaced under the same namespace as the controller/policy. Looking back, this seems to have been left out when I simplified my code - apologies.
Is there a way to make this work with action_policy (without explictly mentioning the model on authorize!)?
my model is also namespaced under the same namespace as the controller/policy
Ok, that's the answer.
You can override the #implicit_authorization_target for your controllers to take into account namespacing like this:
def implicit_authorization_target
controller_path.classify.safe_constantize
end
thankyou