Rails 5 管理来自 monad 的结果

Rails 5 manage result from monads

我已经安装了 Rails 5 个应用 dry-monads。 Monad 用于在 AppointmentsController 中的 create 操作中创建 Appointment 对象。它们在最后一步中 return SuccessFailure 具有以下结构:

# services/appointments/create.rb
(...)
def call
  Success(appointment_params: appointment_params)
    (...)
    .bind(method(:save_appointment))
end

private

def save_appointment(appointment)
  if appointment.save
    Success(appointment)
  else
    Failure(failure_appointments: appointment, appointments_errors: appointment.errors.full_messages)
  end
end

每次操作后(成功或失败)我想发送一封电子邮件并在AppointmentsController中显示相应的json:

class Api::AppointmentsController < ApplicationController
  def create
    succeeded_appointments = []
    failure_appointments = []
    appointments_errors = []

    batch_create_appointments_params[:_json].each do |appointment_params|
      appointment = ::Appointments::Create.new(appointment_params).call

      if appointment.success?
        succeeded_appointments << appointment.value!
      else
        failure_appointments << appointment.failure[:failure_appointments] &&
          appointments_errors << appointment.failure[:appointments_errors]
      end
    end

    if failure_appointments.any?
      AppointmentMailer.failed_mail(email, failure_appointments.size, appointments_errors).deliver_now

      render json: {
        error: appointments_errors.join(', '),
      }, status: :bad_request
    elsif succeeded_appointments.any?
      AppointmentMailer.success_mail(email, succeeded_appointments.size).deliver_now

      render json: {
        success: succeeded_appointments.map do |appointment|
                   appointment.as_json(include: %i[car customer work_orders])
                 end,
      }
    end
  end

我想知道是否有更好、更快的方法来记录这些错误,而不是像在 create行动?到目前为止,创建操作看起来很重。

为批量创建创建单独的服务对象:

# services/appointments/bulk_create.rb
class Appointments::BulkCreate
  def initialize(bulk_params)
    @bulk_params = bulk_params
  end

  def call
    if failed_results.any?
      AppointmentMailer.failed_mail(email, failed_results_errors.size, failed_results_errors).deliver_now

      Failure(failed_results_errors.join(', '))
    else
      AppointmentMailer.success_mail(email, success_appointments.size).deliver_now

      Success(success_appointments)
    end
  end

  private

  attr_reader :bulk_params

  def failed_results
    results.select(&:failure?)
  end

  def success_results
    results.select(&:success?)
  end

  def success_appointments
    @success_appointments ||= success_results.map do |appointment|
      appointment.as_json(include: %i[car customer work_orders])
    end
  end

  def failed_results_errors
    @failed_results_errors ||= failed_results.map do |failed_result|
      failed_result.failure[:appointments_errors]
    end
  end

  def results
    @results ||= bulk_params.map do |appointment_params|
      ::Appointments::Create.new(appointment_params).call
    end
  end
end

那么您的控制器将如下所示:

class Api::AppointmentsController < ApplicationController
  def create
    result = ::Appointments::BulkCreate.new(batch_create_appointments_params[:_json]).call

    if result.success?
      render json: { success: result.value! }, status: :ok
    else
      render json: { error: result.failure }, status: :bad_request
    end
  end
end