使用JQuery在Rails中生成一个表单中的嵌套对象4

时间:2014-02-04 03:11:43

标签: javascript jquery ruby-on-rails-4

使用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=\"&quot;$1,000,000&quot;\" 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

2 个答案:

答案 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。可能不是错误,但看起来可能是一个疏忽。也许你打算在fff

中合并

此外,这是一个三重嵌套表单的示例,它将新项目添加到表格中的偶数。可能有助于看看:

这是我们用于添加/删除项目的JavaScript。

https://github.com/alukima/TooManyChips/blob/master/app/assets/javascripts/add_item.js

events'cre​​ate 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