You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Rails+JavaScript无gem实现同时创建父模型与动态数量子模型

核心问题说明

你当前直接克隆DOM的方式会导致所有Tape输入字段的name属性中的索引值完全相同,Rails解析嵌套参数时会把重复索引的参数互相覆盖,所以无论你新增多少个字段,最终只能保存最后一个子模型,按以下步骤修改即可实现动态数量子模型的同步创建:


步骤1:修改控制器代码

调整默认初始化逻辑,补充必填的嵌套参数校验:

def new
  @paper = Paper.new
  # 自定义默认显示的输入组数量,这里设为1组即可
  1.times { @paper.tapes.build }
end

def create
  @paper = Paper.new(paper_params)
  @paper.user_id = current_user.id
  if @paper.save
    redirect_to action_list_paper_path(@paper.id)
  else
    render 'new'
  end
end

private
# 必须补充嵌套参数的白名单配置
def paper_params
  params.require(:paper).permit(:content, tapes_attributes: [:id, :label, :_destroy])
end

步骤2:修改视图代码

替换gem专属的表单方法,修正重复ID问题,新增删除标记字段:

<!-- 把nested_form_for改为Rails原生的form_for,不需要依赖额外gem -->
<%= form_for(@paper) do |f| %>
 <div class="container">
<%= stylesheet_link_tag 'papers', media: 'all', 'data-turbolinks-track': 'reload' %>
  <div class="paper_form">
    <div class="col-md-6">
      <%= f.label(:content, "Name") %>
      <%= f.text_area :content %>
    </div>
   </div>
 </div>

 <div class="tape_form">
   <%= f.fields_for :tapes do |tape| %>
    <!-- 把原来的id改为class,避免克隆后出现重复ID -->
    <div class="input_pluralBox">
      <div class="input_plural">
        <div class="col-md-4">
         <%= tape.label :label %>
         <%= tape.text_field :label %>
         <!-- 新增删除标记隐藏字段,支持提交时删除对应子项 -->
         <%= tape.hidden_field :_destroy, class: 'tape-destroy' %>
        </div>
      </div>
      <input type="button" value="+" class="add pluralBtn">
      <input type="button" value="-" class="del pluralBtn">
    </div>
  <% end %>
 </div>
 <!-- 补充提交按钮 -->
 <div class="form-submit">
  <%= f.submit "保存" %>
 </div>
<% end %>

步骤3:修改JS代码

克隆元素时动态更新索引值,保证每个字段的参数标识唯一:

<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script type="text/javascript">
$(document).on("click", ".add", function() {
    const $parent = $(this).parent();
    const $newBox = $parent.clone(true);
    // 用当前输入组总数作为新组的唯一索引
    const newIndex = $('.input_pluralBox').length;
    // 批量更新新组内所有字段的name、id属性的索引值
    $newBox.find('input, select, textarea').each(function() {
        const oldName = $(this).attr('name');
        if (oldName) {
            const newName = oldName.replace(/\[tapes_attributes\]\[\d+\]/, `[tapes_attributes][${newIndex}]`);
            $(this).attr('name', newName);
        }
        const oldId = $(this).attr('id');
        if (oldId) {
            const newId = oldId.replace(/_tapes_attributes_\d+_/, `_tapes_attributes_${newIndex}_`);
            $(this).attr('id', newId);
        }
        // 清空新输入框的原有值
        $(this).val('');
    });
    $newBox.insertAfter($parent);
});

$(document).on("click", ".del", function() {
    const $target = $(this).parent();
    if ($('.input_pluralBox').length > 1) {
        // 新增的未保存子项直接移除即可
        $target.remove();
        // 如果是编辑页面要删除已存在的子项,把上面一行替换为下面两行即可
        // $target.find('.tape-destroy').val('1');
        // $target.hide();
    }
});
</script>

内容的提问来源于stack exchange,提问作者frankyorg

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.06 04:51:00