Что такое "путь рельсов" для доступа к ресурсу в before_action контроллера - PullRequest
0 голосов
/ 12 марта 2020

Я использую Pundit для авторизации действий в моих контроллерах. Моя первая попытка состояла в том, чтобы авторизовать модель в hoook after_action:

class CompaniesController < InheritedResources::Base
  after_action :authorize_company, except: :index

  def authorize_company
    authorize @company
  end

Это позволило мне использовать действия контроллера по умолчанию, которые определяют @company, чтобы я не обращался к базе данных дважды. Но это плохо для деструктивных действий, потому что это не будет разрешать действие после Я уже испортил базу данных.

Итак, я перешел на использование before_action hook:

class CompaniesController < InheritedResources::Base
  before_action :authorize_company, except: :index

  def authorize_company
    @company = Company.find(params.require(:id))
    authorize @company
  end

Теперь я не разрешаю неавторизованным людям удалять ресурсы и т. д. c ... но я дважды обращаюсь к базе данных. Есть ли в любом случае доступ к @company без двойного обращения к базе данных?

Ответы [ 2 ]

1 голос
/ 13 марта 2020

Поскольку вы просите "путь рельсов", вы должны настроить его на "старые рельсы" без InheritedResources.

class CompaniesController < ApplicationController
  before_action :authorize_company, except: [:new, :index]

  def new
    @company = authorize(Company.new)
  end

  def index
    @companies = policy_scope(Company)
  end

  # ...

  private

  def authorize_company
    @company = authorize(Company.find(params[:id]))
  end
end

Если вы действительно хотите чтобы использовать обратные вызовы, вы должны сделать это следующим образом:

class CompaniesController < ApplicationController
  before_action :authorize_company, except: [:new, :index]
  before_action :authorize_companies, only: [:index]
  before_action :build_company, only: [:new]

  # ...

  private

  def authorize_company
    @company = authorize(Company.find(params[:id]))
  end

  def authorize_companies
    @companies = policy_scope(Company)
  end

  def build_companies
    @company = authorize(Company.new)
  end
end

Да, вы можете написать один метод обратного вызова с тремя ветвями кода, но это имеет меньшую циклическую сложность c, и каждый метод выполняет одну работу.

0 голосов
/ 13 марта 2020

Оказывается, у контроллеров рельсов есть resource, если модель существует, и build_resource для таких действий, как new.

class CompaniesController < InheritedResources::Base
  before_action :authorize_company, except: :index

  private

    def authorize_company
      authorize resource
    rescue ActiveRecord::RecordNotFound
      authorize build_resource
    end
end
...