我使用Pundit gem(Devise和Rolify)來限制對基於登錄用戶角色的信息的訪問。Pundit中的實現範圍
此時,我爲我的用戶模型定義了三個角色:管理員,客戶端管理員和客戶管理員。
用戶屬於客戶。 客戶has_many用戶。
我在索引客戶模型下成功實施了一項權威政策。管理員和客戶端管理員可以查看所有客戶。客戶管理員只能看到他們自己的記錄。
問題在於我試圖限制客戶控制器的顯示方法。管理員和客戶端管理員可以查看所有客戶。但是,客戶管理員應該只能看到他自己的記錄。 但是,客戶管理員可以輸入URL中的任何ID並查看任何客戶記錄。
我在範圍界定上很模糊。我的理解是,政策方法(即索引和顯示)將限制世衛組織執行這些行動,而範圍界定方法限制可以獲得哪些記錄。我無法爲上述場景組成正確的範圍。
這裏的客戶控制器:
class CustomersController < ApplicationController
before_action :set_customer, only: [:show, :edit, :update, :destroy]
after_action :verify_authorized
# GET /customers
# GET /customers.json
def index
@customers = policy_scope(Customer)
authorize Customer
end
# GET /customers/1
# GET /customers/1.json
def show
authorize @customer
end
# GET /customers/new
def new
@customer = Customer.new
authorize @customer
end
# GET /customers/1/edit
def edit
authorize @customer
end
# POST /customers
# POST /customers.json
def create
@customer = Customer.new(customer_params)
authorize @customer
respond_to do |format|
if @customer.save
format.html { redirect_to @customer, notice: 'Customer was successfully created.' }
format.json { render :show, status: :created, location: @customer }
else
format.html { render :new }
format.json { render json: @customer.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /customers/1
# PATCH/PUT /customers/1.json
def update
authorize @customer
respond_to do |format|
if @customer.update(customer_params)
format.html { redirect_to @customer, notice: 'Customer was successfully updated.' }
format.json { render :show, status: :ok, location: @customer }
else
format.html { render :edit }
format.json { render json: @customer.errors, status: :unprocessable_entity }
end
end
end
# DELETE /customers/1
# DELETE /customers/1.json
def destroy
authorize @customer
@customer.destroy
respond_to do |format|
format.html { redirect_to customers_url, notice: 'Customer was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_customer
@customer = Customer.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def customer_params
params.require(:customer).permit(:name, :parent_customer_id, :customer_type, :active, :currency)
end
end
這裏是客戶政策:
class CustomerPolicy < ApplicationPolicy
def index?
# Admins, ClientAdmins, and CustomerAdmins can index customers (see Scope class for filters)
@user.has_role? :admin or @user.has_role? :client_admin or @user.has_role? :customer_admin
end
def show?
# Admins, ClientAdmins, and CustomerAdmins can see any customer details
@user.has_role? :admin or @user.has_role? :client_admin or @user.has_role? :customer_admin
end
def update?
# Only Admins and ClientAdmins can update customer details
@user.has_role? :admin or @user.has_role? :client_admin
end
def destroy?
@user.has_role? :admin or @user.has_role? :client_admin
end
class Scope < Struct.new(:user, :scope)
def resolve
if (user.has_role? :admin or user.has_role? :client_admin)
# Admins and ClientAdmins can see all Customers
scope.where(:parent_id => nil)
elsif user.has_role? :customer_admin
# Customer Admins can only see their own Customer
scope.where(:id => user.customer) # THIS DOES NOT APPEAR TO GET INVOKED BY THE SHOW METHOD OF THE CONTROLLER
end
end
def show?
# NOT SURE WHAT TO PUT IN HERE
end
end
end
成功!感謝railscard給我的啓發,訣竅是修改節目?方法類似下面的客戶策略文件:
def show?
# Admins, ClientAdmins, and CustomerAdmins can see any customer details
# Students cannot see customer details
return true if user.has_role?(:admin) || user.has_role?(:client_admin)
return true if user.customer_id == @record.id && user.has_role?(:customer_admin)
false
end
注意,我不得不使用@record實例變量,因爲這就是應用程序的策略類用來指由授權方法傳遞的記錄。
謝謝!
在此先感謝您的幫助。我明白你的意思 - 當我希望返回一個集合時,應該使用範圍。但是我不確定把你描述的這個方法放在哪裏。這是在客戶的政策?抱歉。這讓我感到完全啞巴。 –
要清楚:我試圖在客戶策略文件中插入方法,並且我沒有看到任何行爲差異。我想我不確定什麼會觸發該方法。 –
GOT IT!你是我的英雄,非常感謝你。我會在問題中發佈修改過的代碼,但這幾乎是正確的答案。 –