Как обрабатывать и сушить проверки в контроллерах Rails - PullRequest
0 голосов
/ 04 октября 2018

Я пытаюсь найти элегантный способ обработки некоторых общих проверок между двумя контроллерами.

Пример:

У меня есть два контроллера учетных записей.Один для синхронной обработки учетных записей для пользователя (с использованием, например, PORO, который содержит логику для этого случая), а другой - для асинхронной обработки ассоциации с рабочим. Пожалуйста, предположите, что логика отличается в каждом сценарии, и тот факт, что синхронизация / асинхронность не единственная разница.

Тогда у меня есть два контроллера:

module Accounts
  class AssociationsController < ApplicationController
    def create
      return already_associated_account_error if user_has_some_account_associated?
      # action = call some account association PORO
      render json: action.response, status: action.status_code
    end

    private

    def user_has_some_account_associated?
      params[:accounts].any? { |account_number| user_account_associated?(account_number) }
    end

    def user_account_associated?(account_number)
      current_user.accounts.exists?(number: account_number)
    end

    def already_associated_account_error
      render json: 'You already have associated one or more accounts', status: :unprocessable_entity
    end
  end
end

Теперь у меня есть другой контроллер, в котором я хотел бы применить ту же проверку:

module Accounts
  class AsyncAssociationsController < ApplicationController
    def create
      return already_associated_account_error if user_has_some_account_associated?
      # Perform asynchronously some account association WORKER
      render json: 'Your request is being processed', status: :ok
    end

    private

    def user_has_some_account_associated?
      params[:accounts].any? { |account_number| user_account_associated?(account_number) }
    end

    def user_account_associated?(account_number)
      current_user.accounts.exists?(number: account_number)
    end

    def already_associated_account_error
      render json: 'You already have associated one or more accounts', status: :unprocessable_entity
    end
  end
end

...

КАК и ГДЕ я мог бы разместить логику проверки вТОЛЬКО ОДИН SPOT и использовать его в обоих контроллерах?Сначала я подхожу к проблеме, но не уверен, предназначены ли они только для этих случаев логики валидации.

Ответы [ 2 ]

0 голосов
/ 04 октября 2018

Для этого вы должны использовать проблемы.Это то, для чего они предназначены.

В каталоге controllers создайте каталог concerns (если его там еще нет), а внутри него создайте файл association_concern.rb с таким содержанием:

module AssociationConcern
  extend ActiveSupport::Concern

  private

  def user_has_some_account_associated?
    params[:accounts].any? { |account_number| user_account_associated?(account_number) }
  end

  def user_account_associated?(account_number)
    current_user.accounts.exists?(number: account_number)
  end

  def already_associated_account_error
    render json: 'You already have associated one or more accounts', status: :unprocessable_entity
  end

end

Все, что является общим для контроллеров, может иметь значение

Тогда в ваших контроллерах просто include AssociationConcern

class AssociationsController < ApplicationController
  include AssociationConcern

  def create
    return already_associated_account_error if user_has_some_account_associated?
    # action = call some account association PORO
    render json: action.response, status: action.status_code
  end

end
0 голосов
/ 04 октября 2018

Заставьте их наследовать от какого-то нового контроллера и добавьте before_action, например:

module Accounts
  class AbstractAssociationsController < ApplicationController
    before_action :check_for_associated_account, only: [:create]

    def check_for_associated_account
      if user_has_associated_account?
        render json: 'You already have associated one or more accounts', status: :unprocessable_entity
      end
    end
  end
end

module Accounts
  class AssociationsController < AbstractAssociationsController
    def create
      # action = call some account association PORO
      render json: action.response, status: action.status_code
    end
  end
end

Затем, в зависимости от того, действительно ли логика отличается, вы можете определить user_has_associated_account? в любом из этихабстрактный контроллер, отдельные контроллеры или делегирование его некоторому классу PORO.

...