Реализация прицелов в Пундит

Я использую гем Pundit (вместе с Devise и Rolify), чтобы ограничить доступ к информации на основе зарегистрированных ролей пользователей.

В настоящее время для моей модели User определены три роли: Admin, Client Admin и Customer Admin.

Пользователь принадлежит_ Клиенту. Клиент has_many Пользователи.

Я успешно внедрил политику Pundit, когдаиндексирование Модель Заказчика. Администраторы и администраторы клиентов могут видеть всех клиентов. Администратор клиента может видеть только свою СОБСТВЕННУЮ запись.

Проблема заключается в том, когда я пытаюсь ограничитьшоу Метод Контролера Заказчика. Администраторы и администраторы клиентов могут видеть всех клиентов. Однако администратор клиента должен иметь возможность видеть только свою собственную запись.Но в нынешнем виде Администратор клиента может ввести любой идентификатор в URL и просмотреть любую запись Клиента.

Я нечеткий в области видимости. Насколько я понимаю, методы Политики (то есть индекс? И показать?) Предназначены для ограничения ВОЗ, которая может выполнять эти действия, а методы Скопинга ограничивают, КАКИЕ ЗАПИСИ могут быть получены. У меня проблемы с составлением правильной области действия для вышеупомянутого сценария.

Вот контроллер клиента:

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, поскольку именно это использует класс политики приложения для ссылки на запись, передаваемую методом authorize.

Спасибо!!

Ответы на вопрос(2)

Ваш ответ на вопрос