Rails控制器多循环创建方法报错:undefined method `each' for nil:NilClass
问题分析
undefined method 'each' for nil:NilClass错误:当某个时间范围未选择任何日期时,value[:days]为nil,直接调用each触发报错。- 无效日程ID:传入的
schedule_ids包含空字符串"",会生成无关联日程的无效记录。 - 记录保存不完整:循环中每次覆盖
@scheduleevent变量,最终仅保存最后一条记录,前面的实例未执行保存操作。
修复步骤
1. 修正创建方法逻辑
修改create方法,过滤无效数据、处理nil情况,同时确保所有记录都被保存:
def create # 过滤掉空的日程ID valid_schedule_ids = scheduleevent_params[:schedule_ids].reject(&:blank?) # 追踪所有记录的保存状态 all_saved = true valid_schedule_ids.each do |schedule_id| scheduleevent_params[:schedtimeranges_attributes].each do |key, value| # 跳过无日期的时间范围 next unless value[:days].present? value[:days].each do |day| @scheduleevent = Scheduleevent.new( schedule_id: schedule_id, day: day, title: scheduleevent_params[:title], description: scheduleevent_params[:description], start_date: scheduleevent_params[:start_date], end_date: scheduleevent_params[:end_date], start_time: value[:start_time], end_time: value[:end_time], user_id: current_user.id ) # 记录保存失败的情况 all_saved = false unless @scheduleevent.save end end end respond_to do |format| if all_saved format.turbo_stream format.html { redirect_to scheduleevents_url, notice: "所有日程事件已成功创建。" } format.json { render json: { message: "所有日程事件已成功创建" }, status: :created } else format.html { render :new, status: :unprocessable_entity } format.json { render json: @scheduleevent.errors, status: :unprocessable_entity } end end end
2. 确认参数许可配置
确保scheduleevent_params正确允许嵌套的days数组参数:
def scheduleevent_params params.require(:scheduleevent).permit( :title, :day, :start_time, :end_time, :description, :start_date, :end_date, :repeattypeid, :hexcolor, :scheduleinstid, :locked, schedule_ids: [], schedtimeranges_attributes: [ :id, :start_time, :end_time, :repeattype, :_destroy, days: [] ] ) end
3. 前端可选优化(避免空提交)
在表单提交前添加验证,确保每个时间范围至少选择一个日期,比如在Stimulus控制器中添加逻辑:
// app/javascript/controllers/nested_form_controller.js import { Controller } from "@hotwired/stimulus" export default class extends Controller { submit(event) { const wrappers = this.element.querySelectorAll('.nested-form-wrapper') let isValid = true wrappers.forEach(wrapper => { const days = wrapper.querySelectorAll('input[name*="[days]"]:checked') if (days.length === 0) { isValid = false alert('每个时间范围至少选择一个日期') } }) if (!isValid) event.preventDefault() } }
然后在表单标签添加data-action="submit->nested-form#submit"。
内容的提问来源于stack exchange,提问作者spacerobot
相关产品推荐
相关产品推荐

