Rails表单保存失败后视图循环报错:路由缺失id参数
问题分析与解决方案
看起来你遇到的问题有两个核心原因,咱们一步步拆解:
1. 循环里错用了全局的@nurse变量
你生成链接的代码里,first: @nurse.first, last: @nurse.last这里用的是表单里的新护士实例@nurse,而不是当前循环中的现有护士对象nurse。当表单保存失败时,@nurse是那个验证没通过的未保存对象,它的属性可能不符合预期,甚至会干扰链接参数的正确性。
2. 未保存的护士被混入了@nurses集合
在create动作里,你用了@shift.nurses.build(nurse_params)——ActiveRecord的build方法会把这个新创建的、还没存进数据库的护士对象直接加到@shift.nurses集合里。当保存失败渲染:new模板时,@nurses = @shift.nurses就包含了这个没有id的护士,循环到它的时候,nurse.id是nil,直接导致路由生成失败(因为你的路由要求必须有id参数)。
修复步骤
第一步:修正链接的参数引用
把链接里的@nurse改成循环变量nurse,确保用的是当前循环中现有护士的属性:
<ul> <% @nurses.each do |nurse| %> <li> <%= link_to "#{nurse.first} #{nurse.last}", holiday_schedule_connect_ranking_path(@holiday_schedule.id, nurse.id, first: nurse.first, last: nurse.last), method: :patch %> </li> <% end %> </ul>
第二步:确保@nurses只包含已保存的护士
在create动作的失败分支里,我们需要排除那个未保存的新护士对象,有两种简单的方式:
方式一:重新从数据库加载护士(推荐)
用reload方法重置关联集合,只获取数据库里已存在的护士:
def create @holiday_schedule = HolidaySchedule.find(params[:holiday_schedule_id]) @shift = @holiday_schedule.shift @nurse = @shift.nurses.build(nurse_params) respond_to do |format| if @nurse.save @disconnected_rankings = @holiday_schedule.rankings.where('first = ? AND last = ?', @nurse.first, @nurse.last) @nurse.connect_rankings(@disconnected_rankings); format.html { redirect_to shift_path(@shift), notice: 'Set of rankings resolved.' } format.json { redirect_to shift_path(@shift), notice: 'Set of rankings resolved.' } else # 重新加载已保存的护士,排除未保存的新对象 @nurses = @shift.nurses.reload format.html { render :new } format.json { redirect_back fallback_location: root_path, notice: "Nurse couldn't be saved." } end end end
方式二:过滤内存中的未保存对象
如果你不想额外查询数据库,可以直接从集合里筛选出已存进数据库的护士:
@nurses = @shift.nurses.select(&:persisted?)
为什么单独渲染第一个护士能正常工作?
当你手动取@nurses.first时,这个对象是数据库里已存在的护士(有合法的id),哪怕@nurse的参数不对,路由生成时的核心id参数是有效的,所以不会报错。但循环时会遍历到那个未保存的护士,才会暴露问题。
内容的提问来源于stack exchange,提问作者Eojo
相关产品推荐
相关产品推荐

