2013-08-24 63 views
2

所以我決定嘗試pundit用戶授權解決方案。我不知道如何使用policy幫手圖,其中一個實例變量可能是零,如下面的簡單情況:在沒有實例變量的情況下使用Pundit中的策略助手

應用程序/視圖/項目/ index.html.slim

h1 Projects 
(...) 
- if policy(@project).create? 
    = link_to 'New Project', new_project_path 

應用程序/控制器/projects_controller.rb

(...) 
def index 
    @projects = Project.all 
end 
(...) 

應用程序/政策/ project_policy.rb

class ProjectPolicy < Struct.new(:user, :project) 
    def create? 
    user.has_role? :admin 
    end 

我想說明的項目#索引頁面中的「新建項目」鏈接,但我沒有可用@project實例變量的這種觀點,得到一個錯誤:

Pundit::NotDefinedError in Projects#index

unable to find policy NilClassPolicy for

錯誤出現顯然是因爲我做的通過@project實例變量是零,因此有一個NilClass,這顯然我沒有必要授權。

我發現2種解決方法,此問題使其正常運行,但他們都不似乎是適當的:

視圖
  1. 利用現有@projects變量,即:policy(@projects[0])
  2. 加一行到項目#index控制器操作,定義這個實例變量,例如。 @project = Project.new(或直接在視圖類似於以上:policy(Project.new)

首先溶液將導致在@projects陣列相同的錯誤將是空的,而第二個冗餘創建實例變量。所有的政策幫手需要知道的是我想要強制執行授權邏輯的類。

任何建議,以正確的方式來實現它?

回答

5

您提出的第二個解決方案就是我所做的。

- if policy(@project).create? 
    = link_to 'New Project', new_project_path 

策略檢查這裏的新紀錄應該使用Project.new(不管它是分配給一個實例變量與否)

- if policy(Project.new).create? 
    = link_to 'New Project', new_project_path 

這樣或那樣的Project一個實例必須被傳遞到policy助手,以便權威人士導出策略類ProjectPolicy做就create?檢查查找。當你通過nil這就是爲什麼你看到權威派生NilClassPolicy

+0

完美,非常感謝! – CloudRide

3

通常,個別實例與類中的所有其他實例具有相同的策略 - 事實上這正是Pundit工作的正常方式。在這種情況下,你真的不關心屬於特定實例的策略;相反,你正在尋找一類對象的策略。

policy方法使用this find method來標識您的對象的策略類。

def find 
    if object.respond_to?(:policy_class) 
    object.policy_class 
    elsif object.class.respond_to?(:policy_class) 
    object.class.policy_class 
    else 
    klass = if object.respond_to?(:model_name) 
     object.model_name 
    elsif object.class.respond_to?(:model_name) 
     object.class.model_name 
    elsif object.is_a?(Class) 
     object 
    else 
     object.class 
    end 
    "#{klass}Policy" 
    end 
end 

您可以將任何對象傳遞給策略方法。由於類是對象,因此您可以將類傳入。在find方法中,第一個條件檢查您傳遞的對象是否響應policy_class,因此您可以在Project類中定義一個名爲policy_class的方法,並讓該方法返回您的ProjectPolicy類。

class Project < ActiveRecord::Base 
    def self.policy_class 
    ProjectPolicy 
    end 
end 

如果不定義policy_class方法,那麼前兩個條件會失敗,然後找到方法將試圖建立一個策略類的名字。它首先查看object.model_name。如果你在Rails中,並且你的模型擴展了ActiveModel :: Naming(ActiveRecord :: Base),那麼它已經響應model_name,如果你正在做典型的Rails-ey的東西,那麼這個名字就是你想要:它會返回"Project"。查找方法然後將「策略」附加到該末尾以製作"ProjectPolicy"。如果是其他對象,則使用該對象的名稱,並且這對大多數情況也適用。

或者,您可以傳遞任何原型對象,該對象表示您想要爲其策略的對象類型。這意味着您可以使用Policy.new創建一個,或者您可以從@policies陣列中選取一個。如你所說,這些選項有缺點。

有很多選項可供您選擇。沒有特別「正確」的方式。我喜歡在這樣的情況下通過類,因爲它具有最大的語義意義。

相關問題