更新BusinessHour时,关联WorkingHour存在则更新否则创建的实现
解决方案
要实现更新business_hours时同步处理working_hours(存在则更新、不存在则创建,且确保7天记录齐全),可以通过调整模型验证、嵌套属性配置,以及在控制器中补充逻辑来完成,具体修改如下:
1. 调整模型代码
修改WorkingHour模型
仅在新建记录时检查day是否重复,避免阻止更新操作:
class WorkingHour < ApplicationRecord belongs_to :business_hour validates :day, inclusion: { in: %w(mon tue wed thu fri sat sun) } # 仅在新建记录时校验day唯一性 validate :validate_day, on: :create def validate_day if business_hour.working_hours.where(day: self.day).exists? errors.add(:day, "has already been added") end end end
修改BusinessHour模型
调整嵌套属性配置,支持更新已有记录并过滤空属性:
class BusinessHour < ApplicationRecord has_many :working_hours, class_name: "WorkingHour" belongs_to :organization # 移除update_only,添加空属性过滤规则 accepts_nested_attributes_for :working_hours, allow_destroy: false, reject_if: :all_blank end
2. 调整控制器代码
更新update方法逻辑
添加匹配已有记录、确保7天记录齐全的处理逻辑:
class Api::V1::Admin::BusinessHoursController < Api::BaseController def update @organization.build_business_hours unless @organization.business_hours @business_hour = @organization.business_hours # 为传入的working_hour匹配已有记录ID,实现更新而非重复创建 process_working_hours_attributes if @business_hour.update(business_hour_params) # 确保周一到周日的working_hour记录全部存在 ensure_all_working_days_exist render status: :ok, json: { notice: I18n.t("resource.update", resource_name: "Organization") } else # 返回所有验证错误(包含business_hours和working_hours的错误) all_errors = @business_hour.errors.full_messages + @business_hour.working_hours.flat_map(&:errors).flat_map(&:full_messages) render status: :unprocessable_entity, json: { errors: all_errors } end end private def business_hour_params params.require(:business_hours).permit( :enabled, :away_message, # 新增允许:id参数,用于匹配已有记录 working_hours_attributes: [:id, :day, :start_time, :end_time] ) end # 为传入的working_hour属性匹配对应day的已有记录ID def process_working_hours_attributes return unless params.dig(:business_hours, :working_hours_attributes) params[:business_hours][:working_hours_attributes].each do |wh_attrs| next unless wh_attrs[:day].present? existing_wh = @business_hour.working_hours.find_by(day: wh_attrs[:day]) wh_attrs[:id] = existing_wh.id if existing_wh.present? end end # 补充缺失的工作日记录(默认时间可根据业务需求调整) def ensure_all_working_days_exist all_days = %w(mon tue wed thu fri sat sun) existing_days = @business_hour.working_hours.pluck(:day) (all_days - existing_days).each do |day| @business_hour.working_hours.create!( day: day, start_time: nil, # 可替换为业务默认开始时间 end_time: nil # 可替换为业务默认结束时间 ) end end end
逻辑说明
- 匹配已有记录:
process_working_hours_attributes会为每个传入的工作日属性,匹配对应day的已有记录ID,Rails会自动根据ID执行更新操作,而非创建重复记录。 - 确保7天记录齐全:
ensure_all_working_days_exist会检查当前business_hour的工作日记录,自动补充缺失的日期记录。 - 错误处理优化:合并返回
business_hours和working_hours的所有验证错误,便于前端定位问题。
内容的提问来源于stack exchange,提问作者Mohit Harshan
相关产品推荐
相关产品推荐

