Gültigkeitsbereiche in Pundit implementieren

Ich benutze das Pundit-Juwel (mit Devise und Rolify), um den Zugriff auf Informationen basierend auf angemeldeten Benutzerrollen einzuschränken.

Derzeit sind drei Rollen für mein Benutzermodell definiert: "Admin", "Client-Admin" und "Kunden-Admin".

Ein Benutzer gehört einem Kunden. Kunde hat_viele Benutzer.

Ich habe eine Pundit-Richtlinie erfolgreich implementiert, wennIndizierung das Kundenmodell. Administratoren und Kundenadministratoren können alle Kunden sehen. Der Kundenadministrator kann nur seinen EIGENEN Datensatz anzeigen.

Das Problem liegt, wenn ich versuche, das einzuschränkenShow Methode des Kundencontrollers. Administratoren und Kundenadministratoren können alle Kunden sehen. Der Kundenadministrator sollte jedoch nur seinen eigenen Datensatz sehen können.Im jetzigen Zustand kann der Kundenadministrator jedoch eine beliebige ID in die URL eingeben und alle Kundendatensätze anzeigen.

Ich bin verwirrt über das Scoping. Ich verstehe, dass die Policy-Methoden (d. H. Index? Und show?) Dazu dienen, zu beschränken, dass die WHO diese Aktionen ausführen kann, und die Scoping-Methoden beschränken, WELCHE RECORDS erhältlich sind. Ich habe Probleme, den richtigen Bereich für das obige Szenario zu erstellen.

Hier ist der Kundencontroller:

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

Und hier ist die Kundenrichtlinie:

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

Erfolg!! Dank des Vorsprungs von railscard bestand der Trick darin, die Show zu modifizieren? Methode in der Kundenrichtliniendatei wie folgt:

  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

Beachten Sie, dass ich die Instanzvariable @record verwenden musste, da dies in der Anwendungsrichtlinienklasse verwendet wird, um auf den Datensatz zu verweisen, der von der authorize-Methode übergeben wird.

Vielen Dank!!

Antworten auf die Frage(2)

Ihre Antwort auf die Frage