-->

pundit policies with namespaces

2019-07-16 06:12发布

问题:

I have Question model in my application.

app/models/question.rb

class Question < ActiveRecord::Base
  ...
end

I'm using 'pundit' gem for authorization. There are two controllers to do some changes in questions: one for registered user, one for admin.

I'm trying to create separate policies for controllers.

app/controllers/questions_controller.rb

class QuestionsController < ApplicationController
   ...
end

app/policies/question_policy.rb

class QuestionPolicy < ApplicationPolicy
  ...
end

app/controllers/admin/questions_controller.rb

class Admin::QuestionsController < Admin::ApplicationController
  ...
end

app/policies/admin/question_policy.rb

class Admin::QuestionPolicy < Admin::ApplicationPolicy
  ...
end

When I'm trying to use 'authorize' method in Admin::QuestionsController it uses app/policies/question_policy.rb class not from admin folder.

Gem's documentation says that is should work like I described above (https://github.com/elabs/pundit#namespaced-policies).

Can somebody help me with that?

回答1:

I've created issue in github source code and it was closed with such explanation:

The docs refer to the currently unreleased master branch. You can use it by referring to the github source in your Gemfile.

# Gemfile
gem 'pundit', github: 'elabs/pundit'
A bundle install later your code should work.

You can switch back to a released version on Rubygems as soon as 0.3.0 is out. We're still     discussing a few namespacing issues, but it will come soon.


回答2:

If anyone is still looking for this functionality, I needed it as well for splitting up authorizations between ActiveAdmin and my end-user facing site. I built a Pundit compatible gem for controller-based namespaced authorizations (your policies will work), and I plan to follow any features released for pundit. It also includes an ActiveAdmin adapter.



回答3:

I was trying to get separated policies for the main app and the ActiveAdmin and ended up with a working solution by creating a customized PunditAdapter to be used in config/initializers/active_admin.rb

class NamespacedPunditAdapter < ActiveAdmin::PunditAdapter
  def get_policy(subject, user, resource)
    "ActiveAdmin::#{subject}Policy".constantize.new(user, resource)
  end

  def retrieve_policy(subject)
    case subject
    when nil then get_policy(subject, user, resource)
    when Class then get_policy(subject, user, subject.new)
    else
      if subject.class.to_s.split('::')[0] == 'ActiveAdmin'
        Pundit.policy!(user, subject)
      else
        get_policy(subject.class, user, subject)
      end
    end
  end

  def scope_collection(collection, _action = Auth::READ)
    return collection if collection.class != Class
    scope = "ActiveAdmin::#{collection}Policy::Scope".constantize
    scope.new(user, collection).resolve
  rescue Pundit::NotDefinedError => e
    if default_policy_class && default_policy_class.const_defined?(:Scope)
      default_policy_class::Scope.new(user, collection).resolve
    else
      raise e
    end
  end
end

Another option would be to use an ActiveSupport::Concern as pointed out here