Cocoon gem双层嵌套表单不工作 报spotlight局部变量未定义
Rails Cocoon双层嵌套表单
undefined local variable or method 'spotlight'问题修复 问题根因
- 模型层未配置双层嵌套的关联与
accepts_nested_attributes_for声明,cocoon无法识别嵌套层级的依赖关系 - 视图层直接在
fields_for中传入LifePage.new临时实例,没有绑定父模型@business的关联,导致cocoon动态渲染新增子项时丢失父级上下文,无法正确构建子表单对象 - 手动渲染局部模板时显式传递了
spotlight变量,但cocoon动态渲染时因上下文错误未能传入该变量,触发未定义错误;后续添加的变量存在判断写错了nested-fields容器的闭合位置,拦截了正常的表单字段渲染,导致点击新增按钮只生成空容器
修复步骤
1. 补全模型层关联与嵌套属性配置
三个关联模型按如下结构补全配置,allow_destroy: true是cocoon删除功能必需的配置:
# app/models/business.rb class Business < ApplicationRecord has_one :life_page accepts_nested_attributes_for :life_page, allow_destroy: true end # app/models/life_page.rb class LifePage < ApplicationRecord belongs_to :business has_many :spotlights accepts_nested_attributes_for :spotlights, allow_destroy: true, reject_if: :all_blank end # app/models/spotlight.rb class Spotlight < ApplicationRecord belongs_to :life_page end
2. 调整控制器逻辑,在控制器层初始化关联对象
不要在视图层直接new关联实例,在控制器的new动作中预构建关联对象,同时在strong parameters中放行嵌套属性:
# app/controllers/businesses_controller.rb def new @business = Business.new # 预初始化嵌套对象,供首次表单渲染使用 @business.build_life_page.spotlights.build end private def business_params params.require(:business).permit( # 此处保留Business模型自身的字段参数 life_page_attributes: [ :id, :_destroy, # 此处保留LifePage模型自身的字段参数 spotlights_attributes: [:id, :title, :description, :visible, :optional_caption, :_destroy] ] ) end
3. 修正表单视图_form.html.erb的写法
移除视图层直接new实例的逻辑,改用关联名调用fields_for,确保表单构建器和父模型绑定:
<%= form_for @business, remote: true, html: { id: "newbusinessForm" } do |f|%> <%# 此处保留Business自身的其他表单字段 %> <%= f.fields_for :life_page do |life_page| %> <%= life_page.fields_for :spotlights do |spotlight| %> <%= render 'spotlight_fields', spotlight: spotlight %> <% end %> <div class="links"> <%= link_to_add_association "Add Spotlight", life_page, :spotlights %> </div> <% end %> <%# 此处保留提交按钮等其他表单元素 %> <% end %>
4. 还原子表单局部模板_spotlight_fields.html.erb
移除之前添加的变量存在判断,保证cocoon依赖的.nested-fields容器结构完整:
<div class="nested-fields"> <div class="field"> <%= spotlight.label :title %> <%= spotlight.text_field :title %> <%= link_to_remove_association "Delete", spotlight %> </div> </div>
验证结果
修复后首次加载表单会正常渲染一个空的Spotlight输入项,点击「Add Spotlight」按钮可正常新增带输入框、删除按钮的表单项,不会再出现变量未定义错误、空容器问题。
内容的提问来源于stack exchange,提问作者Hemant Patil
相关产品推荐
相关产品推荐

