Rails 5结合dry-monads的预约批量创建接口代码优化问询
优化方案
核心思路是利用Ruby内置迭代方法避免手动声明临时变量,同时复用dry-monads的返回结构减少冗余存储,优化后代码如下:
class Api::AppointmentsController < ApplicationController def create # 单次遍历拆分成功/失败结果,无需提前声明空数组 result = batch_create_appointments_params[:_json].each_with_object({ success: [], failure: [] }) do |appointment_params, res| appointment = ::Appointments::Create.new(appointment_params).call # 可选:用dry-monads内置的either方法替代if判断,更贴合函数式范式 appointment.either( ->(success_appo) { res[:success] << success_appo }, ->(failure_info) { res[:failure] << failure_info } ) end if result[:failure].any? # 直接从失败结果中提取错误,无需单独维护错误数组 errors = result[:failure].flat_map { _1[:appointments_errors] } AppointmentMailer.failed_mail(email, result[:failure].size, errors).deliver_now render json: { error: errors.join(', ') }, status: :bad_request else AppointmentMailer.success_mail(email, result[:success].size).deliver_now render json: { success: result[:success].as_json(include: %i[car customer work_orders]) } end end end
如果不习惯either写法,也可以保留原有的success?判断逻辑,仅替换迭代部分即可:
result = batch_create_appointments_params[:_json].each_with_object({ success: [], failure: [] }) do |appointment_params, res| appointment = ::Appointments::Create.new(appointment_params).call if appointment.success? res[:success] << appointment.value! else res[:failure] << appointment.failure end end
优化说明
- 去掉了三个预先声明的空数组,用
each_with_object在单次遍历中直接构建结果集合,代码更紧凑 - 复用dry-monads返回的Failure结构中的错误信息,不需要单独维护
appointments_errors数组,减少冗余数据 - 整体时间复杂度和原代码一致为O(n),无额外性能开销
内容的提问来源于stack exchange,提问作者mr_muscle
相关产品推荐
相关产品推荐

