使用Rails 4,并基于Railscast #197我试图通过Javascript动态地使用单个表单创建父对象和子对象。我已经在他的应用程序助手中修改了Ryan Bate的代码(与railscast剧集在同一页面上),这样我就可以在一个表单中创建父对象(BudgetSegment)和子对象(BudgetRatio)。
我希望有人看看我下面的link_to_add_fields
方法并告诉我出了什么问题,因为它不起作用,并告诉我它是否是该功能不起作用的罪魁祸首。可能是因为您无法将builder.fields.for
嵌套在下面的f.fields_for
区块中吗?以下是application_helper.rb
中的相关代码:
def link_to_add_fields(name, f, association, nested_association, locals={})
new_object = f.object.class.reflect_on_association(association).klass.new
nested_new_object = f.object.class.reflect_on_association(association).klass.reflect_on_association(nested_association).klass.new
fields = f.fields_for(association, new_object, :child_index => "new_#{association}") do |builder|
builder.fields_for(nested_association, nested_new_object, :child_index => "new_#{nested_association}") do |nested_builder|
render(association.to_s.singularize + "_row", locals.merge!(:ff => builder, :fff => nested_builder))
end
end
link_to_function(name, "add_fields(this, \"#{association}\", \"#{nested_association}\", \"#{escape_javascript(fields)}\")")
end
这是我的js文件:
function add_fields(link, association, nested_association, content) {
var new_id = new Date().getTime();
var regexp = new RegExp("new_" + association, "g")
var regexp2 = new RegExp("new_" + nested_association, "g")
$(link).parent().parent().parent().before().child(content.replace(regexp, new_id).replace(regexp2, new_id);
}
BudgetSegment和BudgetRatio都在表的同一行。目标是允许用户在单击添加按钮时动态创建新的文本字段行。该行将同时创建两个第一列BudgetSegment文本字段和BudgetRatio文本字段中列的数目不确定向右(为Javascript方法,我只是假设一个BudgetRatio被创建,但你会看到budget_source_controller,最初创建了五个BudgetRatios。
此link_to_add_fields
代码应生成以下部分_budget_segment_row.html.erb
:
<tr class="table-financial">
<td><%= ff.text_field :max, :id => "form-currency", :class => "form-control", :placeholder => '"$1,000,000"', :required => :true %>
</td>
<%= ff.fields_for :budget_ratios do |fff| %>
<td><%= fff.text_field 'box_value', :class => "form-control", :placeholder => 'e.g., "0.75"' %></td>
<td><%= fff.text_field 'pa_value', :id => "pa-value", :class => "form-control", :placeholder => 'e.g., "0.75"' %></td>
<% end %>
</tr>
当我调试时,顶部fields
中定义的link_to_add_fields
变量不返回子(BudgetRatio),只返回父(BudgetSegment)。以下是fields
返回的内容:
"<tr class=\"table-financial\">\n\t<td><input class=\"form-control\" id=\"form-currency\" name=\"budget_source[budget_segments_attributes][new_budget_segments][max]\" placeholder=\""$1,000,000"\" required=\"required\" type=\"text\" />\n\t</td>\n\t\t\n\t\t</tr>"
如您所见,BudgetRatio块中的任何内容都缺失。
这是我的模型结构(仅包括相关部分):
class BudgetSource < ActiveRecord::Base
has_many :budget_segments
accepts_nested_attributes_for :budget_segments
end
class BudgetSegment < ActiveRecord::Base
has_many :budget_ratios
accepts_nested_attributes_for :budget_ratios
end
class BudgetRatio < ActiveRecord::Base
belongs_to :budget_segment
end
下面是BudgetSource的new.html.erb
(省略了一些不相关的部分):
<div class="container">
<div class="info-box">
<%= form_for @budget_source, :method => :post, :url => budget_sources_path do |f| %>
<%= render 'tag_menu_new', :f => f %>
<%= f.fields_for :budget_segments do |ff| %>
<div class="table-responsive">
<table class="table table-condensed table-hover">
<tr class="table-sources-heading">
<th rowspan="2">Budget Segment Maximum</th>
<% scenarios.each do |s| %>
<th colspan="2"><%= s.name %></th>
<% end %>
<th rowspan="2">add</th>
</tr>
<tr class="table-sources-heading">
<% scenarios.each do |s| %>
<th><%= "Box Ratio" %></th>
<th><%= "P&A Ratio" %></th>
<% end %>
</tr>
<%= render 'budget_segment_row', {f: f, ff: ff} %>
<tr>
<td><div class="btn btn-default"><%= link_to_add_fields "Add Row", f, :budget_segments, :budget_ratios, :f => f %></td>
</tr>
</table>
</div>
<% end %>
</div>
<div class="row">
<div class='col-sm-6 col-sm-offset-3'>
<%= f.submit 'Save', :class => "btn btn-success" %>
</div>
</div>
</div>
<% end %>
</div>
以下是budget_sources_controller.rb
:
class BudgetSourcesController < ApplicationController
include ApplicationHelper
require 'debugger'
def new
@budget_source = BudgetSource.new
2.times { @budget_source.budget_sources_genres.build }
@budget_segment = @budget_source.budget_segments.build
scenarios.count.times { @budget_segment.budget_ratios.build }
render 'budget_sources/new'
end
def create
@budget_source = BudgetSource.create(budget_source_params)
@budget_source.update(:user_id => current_user.id)
@budget_source.budget_segments.order(:id).each do |bs|
bs.budget_ratios.order(:id).each_with_index do |br, i|
br.update(scenario_id: i+1)
end
end
render 'show'
end
def show
@budget_source = BudgetSource.find(params[:id])
render 'show'
end
private
def budget_source_params
params.require(:budget_source).permit(:id, :user_id, :name, :description, :territory_id, budget_sources_genres_attributes: [:id, :genre_id, :budget_source_id], budget_segments_attributes: [:id, :max, budget_ratios_attributes: [:id, :box_value, :pa_value, :budget_segment_id, :scenario_id]])
end
end
答案 0 :(得分:1)
虽然这不是我想要的解决方案(我真的想知道为什么你不能使用构建器嵌套对象),我的快速修复是:
我没有在f.fields_for
块中嵌套fields_for do |f|
方法(在视图中是常规的),而是使用[object].object.association.build
方法创建了一个嵌套对象。
你会注意到一个以array
开头的新行,因为我想同时创建一个已定义数量的对象,所以我将iterator
变量传递给基本上只是一个方法的方法整数。这是我修改后的link_to_add_fields
代码:
def add_row(name, f, association, nested_association, iterator)
new_object = f.object.class.reflect_on_association(association).klass.new
fields = f.fields_for(association, new_object, child_index: "new_#{association}") do |bs|
array = eval("iterator.map {bs.object.#{nested_association}.build}")
render(association.to_s.singularize + "_row", {f: f, ff: bs, fff: array})
end
link_to_function(name, "add_fields(this, \"#{association}\", \"#{escape_javascript(fields)}\")")
end
答案 1 :(得分:0)
这可能无法解决您的问题,但它至少对可读性有帮助。试着这样做:
new_object = f.const_get(association).new
nested_new_object = f.const_get(nested_association).new
# new_object = f.object.class.reflect_on_association(association).klass.new
# nested_new_object = f.object.class.reflect_on_association(association).klass.reflect_on_association(nested_association).klass.new
然而,我认为问题可能是你传递的是fff:fff
locals.merge!(:ff => builder, :fff => nested_builder))
我唯一可以看到的fff
就在这个区块内:
<%= ff.fields_for :budget_ratios do |fff| %>
<td><%= fff.text_field 'box_value', :class => "form-control", :placeholder => 'e.g., "0.75"' %></td>
<td><%= fff.text_field 'pa_value', :id => "pa-value", :class => "form-control", :placeholder => 'e.g., "0.75"' %></td>
<% end %>
但是如您所知,块内的fff不是您传递的fff
。可能不是错误,但看起来可能是一个疏忽。也许你打算在f
和ff
此外,这是一个三重嵌套表单的示例,它将新项目添加到表格中的偶数。可能有助于看看:
这是我们用于添加/删除项目的JavaScript。
https://github.com/alukima/TooManyChips/blob/master/app/assets/javascripts/add_item.js
events'create view: https://github.com/alukima/TooManyChips/blob/master/app/views/events/_create_event_form.html.erb
和底部的add_items部分,其中包含第3个嵌套。 https://github.com/alukima/TooManyChips/blob/master/app/views/event_items/_create_event_items_form.html.erb