简体   繁体   English

让Pundit授权在Rails 5上使用命名空间

[英]Getting Pundit authorization working with Namespaces on Rails 5

Question about getting Rails 5 and Pundit authorization working with Namespaces. 关于让Rails 5和Pundit授权使用命名空间的问题。

With Pundit, in the controller I wanted to use policy_scope([:admin, @car] which will use the Pundit policy file located in: app/policies/admin/car_policy.rb . I'm having issues trying to Pundit working with this namespace - without a namespace, it works fine. 使用Pundit,在控制器中我想使用policy_scope([:admin, @car] ,它将使用位于以下位置的Pundit策略文件: app/policies/admin/car_policy.rb 。我在尝试使用Pundit时遇到问题命名空间 - 没有命名空间,它工作正常。

Application is running: 应用正在运行:

  • Rails 5 Rails 5
  • Devise for authentication 设计身份验证
  • Pundit for authorization 专家授权

My namespace is for admins for example. 例如,我的命名空间用于admins

The route.rb file looks like: route.rb文件如下所示:

# config/routes.rb

devise_for :admins

root: 'cars#index'
resources :cars

namespace :admin do
  root 'cars#index'
  resources :cars
end

I've setup a Pundit ApplicationPolicy and to get Namespaces working with Pundit's authorize method: @record = record.is_a?(Array) ? record.last : record 我已经设置了Pundit ApplicationPolicy并让命名空间使用Pundit的authorize方法: @record = record.is_a?(Array) ? record.last : record @record = record.is_a?(Array) ? record.last : record

# app/policies/application_policy.rb

class ApplicationPolicy
  attr_reader :user, :record

  def initialize(user, record)
    @user = user
    @record = record.is_a?(Array) ? record.last : record
  end

  def scope
    Pundit.policy_scope!(user, record.class)
  end

  class Scope
    attr_reader :user, :scope

    def initialize(user, scope)
      @user = user
      @scope = scope
    end

    def resolve
      scope
    end
  end
end

In the Admin::CarsController this works authorize [:admin, @cars] Admin::CarsController这个工作authorize [:admin, @cars]

class Admin::CarsController < Admin::BaseController
  def index
    @cars = Car.order(created_at: :desc)
    authorize [:admin, @cars]
  end

  def show
    @car = Car.find(params[:id])
    authorize [:admin, @car]
  end
end

But I would like to use Policy Scope 但我想使用Policy Scope

class Admin::CarPolicy < ApplicationPolicy
  class Scope < Scope
    def resolve
      if user?
        scope.all
      else
        scope.where(published: true)
      end
    end
  end

  def update?
    user.admin? or not post.published?
  end
end

In the Admin::CarsController Admin::CarsController

class Admin::CarssController < Admin::BaseController
  def index
    # @cars = Car.order(created_at: :desc) without a policy scope
    @cars = policy_scope([:admin, @cars]) # With policy scope / doesn't work because of array.
    authorize [:admin, @cars]
  end

  def show
    # @car = Car.find(params[:id]) without a policy scope
    @car = policy_scope([:admin, @car]) # With policy scope / doesn't work because of array.
    authorize [:admin, @car]
  end
end

I'm getting an error because Pundit isn't looking for the Admin::CarPolicy . 我收到一个错误,因为Pundit没有找到Admin::CarPolicy I presume it's because it's an array. 我认为这是因为它是一个数组。

I thought in the controller I could do something like policy_scope(Admin::Car) but that doesn't work :). 我认为在控制器中我可以做类似policy_scope(Admin::Car)但这不起作用:)。

Any assistant is much appreciated. 非常感谢任何助理。


Update 更新

I found this on the Pundit Github Issues Page: https://github.com/elabs/pundit/pull/391 我在Pundit Github问题页面上找到了这个: https//github.com/elabs/pundit/pull/391

This fixes the namespace handling for policy_scope which is what I wanted. 这修复了policy_scope的名称空间处理,这是我想要的。

It updates the Pudit gem -> policy_scope! 它更新了Pudit gem - > policy_scope! method in lib/pundit.rb . lib/pundit.rb方法。

From: 从:

def policy_scope!(user, scope)
  PolicyFinder.new(scope).scope!.new(user, scope).resolve
end

To: 至:

def policy_scope!(user, scope)
  model = scope.is_a?(Array) ? scope.last : scope
  PolicyFinder.new(scope).scope!.new(user, model).resolve
end

My question is, how do I use this in my Rails application? 我的问题是,如何在我的Rails应用程序中使用它? Is it called overloading or monkey patching? 它被称为重载或猴子修补?

I was thinking adding a pundit.rb in the config/initializer directory and using module_eval but unsure how to do this as the policy_scope! 我在想在config/initializer目录中添加一个pundit.rb并使用module_eval但不确定如何在policy_scope!执行此操作policy_scope! is inside module Pundit and class << self . module Pundit内部和class << self

I thought this would work but it doesn't - presume it is because policy_scope! 我认为这会起作用,但它没有 - 假设这是因为policy_scope! is inside class << self . class << self

Pundit::module_eval do
  def policy_scope!(user, scope)
    model = scope.is_a?(Array) ? scope.last : scope
    PolicyFinder.new(scope).scope!.new(user, model).resolve
  end
end

Medir posted the solution on the Pundit Github Issues Page. Medir在Pundit Github问题页面上发布了该解决方案。

Just change your application_policy.rb to : 只需将application_policy.rb更改为:

class ApplicationPolicy
  index? show?....

  class Scope
    attr_reader :user, :scope

    def initialize(user, scope)
      @user = user
      # @scope = scope
      @scope = scope.is_a?(Array) ? scope.last : scope #This fixes the problem
    end

    def resolve
      scope
    end
  end
end

You can then use : 然后你可以使用:

policy_scope([:admin, @cars])

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM