2017-02-25 59 views
4

獲取使用命名空間的Rails 5和Pundit授權的問題。使用命名空間獲得Pundit授權使用Rails 5

有了Pundit,我想在控制器中使用policy_scope([:admin, @car],它將使用位於app/policies/admin/car_policy.rb中的Pundit策略文件。我在嘗試使用此命名空間的權威人士遇到問題 - 沒有命名空間,它工作正常。

應用程序正在運行:

  • Rails的5
  • 設計認證
  • 權威人士授權

My命名空間是admins例如。

route.rb文件看起來像:

# config/routes.rb 

devise_for :admins 

root: 'cars#index' 
resources :cars 

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

我設置一個權威人士ApplicationPolicy,並獲得名稱空間與Pundit一起工作的authorize方法:@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 

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 

但我想用政策範圍

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 

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 

我得到一個錯誤,因爲Pundit沒有在尋找Admin::CarPolicy。我認爲這是因爲它是一個數組。

我想在控制器中我可以做一些像policy_scope(Admin::Car)但這不起作用:)。

任何助手非常感謝。


更新

我發現這對權威人士Github上的問題頁:https://github.com/elabs/pundit/pull/391

這修正了命名空間處理爲policy_scope這正是我想要的。

它更新lib/pundit.rb中的Pudit gem - >policy_scope!方法。

來源:

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

要:

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

我的問題是,如何我在Rails應用程序中使用它?它被稱爲超載或猴子補丁?

我想加入pundit.rbconfig/initializer目錄和使用module_eval但不確定如何做到這一點的policy_scope!裏面module Punditclass << self

我以爲這會工作,但它不會 - 假設它是因爲policy_scope!是在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 

回答

1

Medir在Pundit Github問題頁上發佈瞭解決方案。

只要改變你的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 

然後,您可以使用:

policy_scope([:admin, @cars])