2014-01-31 51 views
11

我剛剛從CanCan轉到了Pundit。我不確定一些事情,以及如何使用Pundit。例如。如何使用專家範圍?

如果您有可以擁有多個父對象的資源,例如可以說一個目標屬於學生和教師。因此,一個學生可以有很多目標,一個教師可以有很多目標。在控制器索引操作中,您可能會這樣做:

if params[:student_id].present? 
    @account = Student.find(params[:student_id]) 
    @goals = @account.goals 
elsif params[:instructor_id].present? 
    @account Instructor.find(params[:instructor_id]) 
    @goals = @account.goals 
end 

params在策略中不可用,所以需要在此處完成邏輯。我認爲。據我所知,如果您跳過policy_scope,您將在查看目標索引頁面時收到未經授權的錯誤。

請問你:

@goals = policy_scope(@account.goals) 

OR

@goals = policy_scope(Goal.scoped).where(account_id: @account.id) 

什麼,當你把一堆包括在混合的情況發生?

@example = policy_scoped(@school.courses.includes(:account => :user, :teacher)) 

或者當需要訂購...這是正確的嗎? policy_scope(Issue.scoped).order(「created_at desc」)

使用範圍時:什麼是:範圍在這裏?是:範圍正在評估的模型的實例?我試圖通過:範圍訪問它的屬性,但沒有奏效。

class Scope < Struct.new(:user, :scope) 

回答

14

從安全的角度來看這個問題,我可以看到一些值得一提的東西。例如,如果您允許用戶指定參數字段student_idinstructor_id,那麼阻止他們爲其他人傳入ID的是什麼?您不希望讓用戶指定他們是誰,特別是當您將策略基於用戶類型時。

首先,我將實現設計和添加一個名爲instructor一個額外的布爾字段,這將是true當用戶是一個教練,但默認爲false學生。

然後你User s就自動定義了一個instructor?方法,該方法將返回true如果在instructor列中的值是true

然後,您可以添加幫手學生:

def student? 
    !instructor? 
end 

現在用設計(這給了我們訪問current_user變量),我們可以做這樣的事情current_user.instructor?將返回true如果他們的講師。

現在就接受政策本身。我剛開始使用權威人士在幾個星期前,但是這是我在您的情況做:

class GoalPolicy < ApplicationPolicy 
    class Scope < GoalPolicy 
    attr_reader :user, :scope 

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

    def resolve 
     @scope.where(user: @user) 
    end 
    end 
end 

那麼你的(我假設GoalsController類和index方法)方法可以看起來像:

def index 
    policy_scope(Goal) # To answer your question, Goal is the scope 
end 

如果你想訂購,你也可以做

def index 
    policy_scope(Goal).order(:created_at) 
end 

我才意識到,你半年前問這個問題,但是,嘿!也許它會回答其他人的一些問題,也許我會得到一些關於我自己萌芽的專家技能的反饋。