在 Rails 3 应用中,动态添加表单字段是一个常见需求,特别是在需要创建嵌套表单或允许用户添加多个同类项的场合。这通常涉及前端 JavaScript/jQuery 操作和后端 Rails 表单构建的配合。
首先确保你的 Rails 3 应用已经包含了 jQuery(Rails 3 默认使用 Prototype.js,需要手动添加 jQuery)。
在 Gemfile 中添加:
gem 'jquery-rails'
然后运行:
bundle install
rails generate jquery:install
// app/assets/javascripts/application.js
$(document).ready(function() {
$('.add-field').on('click', function(e) {
e.preventDefault();
// 获取当前时间戳作为唯一标识
var timestamp = new Date().getTime();
// 创建新的字段 HTML
var newField = $('<div class="field-wrapper">')
.append('<input type="text" name="items[' + timestamp + '][name]" id="items_' + timestamp + '_name" />');
// 添加到表单中
$('#fields-container').append(newField);
});
});
对应的视图代码:
<!-- app/views/items/_form.html.erb -->
<%= form_for @item do |f| %>
<div id="fields-container">
<!-- 已有字段会在这里 -->
</div>
<a href="#" class="add-field">添加字段</a>
<%= f.submit %>
<% end %>
更推荐的方式是结合 Rails 的 fields_for
方法:
# app/controllers/items_controller.rb
def new
@item = Item.new
3.times { @item.sub_items.build } # 预建3个空子项
end
<!-- app/views/items/_sub_item_fields.html.erb -->
<div class="nested-fields">
<%= f.text_field :name %>
<%= link_to "删除", "#", class: "remove-field" %>
</div>
fields_for
:<!-- app/views/items/_form.html.erb -->
<%= form_for @item do |f| %>
<div id="sub-items">
<%= f.fields_for :sub_items do |sub_item| %>
<%= render 'sub_item_fields', f: sub_item %>
<% end %>
</div>
<%= link_to "添加子项", "#", id: "add-sub-item" %>
<%= f.submit %>
<% end %>
$(document).ready(function() {
$('#add-sub-item').on('click', function(e) {
e.preventDefault();
// 获取当前时间戳
var timestamp = new Date().getTime();
// 创建新的字段 HTML
var newFields = $('<div class="nested-fields">')
.append('<input type="text" name="item[sub_items_attributes][' + timestamp + '][name]" id="item_sub_items_attributes_' + timestamp + '_name" />')
.append('<a href="#" class="remove-field">删除</a>');
$('#sub-items').append(newFields);
});
// 删除字段
$(document).on('click', '.remove-field', function(e) {
e.preventDefault();
$(this).closest('.nested-fields').remove();
});
});
原因:Rails 需要特定的命名约定来处理嵌套属性
解决:确保字段名称格式为 model[nested_attributes][index][attribute]
解决:使用时间戳作为唯一索引,而不是顺序数字
解决:使用事件委托(如上面的 $(document).on('click', '.remove-field', ...)
)
accepts_nested_attributes_for
)没有搜到相关的沙龙