通过ajax渲染表单的部分时未定义的变量'f'

时间:2014-10-07 17:56:32

标签: ruby-on-rails

我的情况是,联系人有多个潜在客户,并且潜在客户属于个人资料。我成功地渲染了表格:

# _form.html.erb
<%= form_for @lead do |f| %>
   <%= f.fields_for :contact do |builder| %>
      <%= render "contact_fields", :f => builder %>
      <%= render "leads_field", f: f %>
    <% end %>
<% end %>

# lead_field.html.erb
<%= f.select :practice_type, PRACTICE_TYPES.collect {|type| [ type, type ] }
<%= f.fields_for :practice do |builder| %>
   <%= render "#{@practice.class.name.underscore}_field", :f => builder %>
<% end %>

上面的页面加载工作正常。但是,用户可以从下拉菜单中选择练习,然后发送ajax请求以重新填充表单,从而构建与该练习的关联:

 $('#lead_practice_type').change(function() {
            $.ajax({
                url: "/leads/new",
                data: {
                    profile_type : $(this).val()
                },
                dataType: "script"
            });
        });

错误发生在new.js.erb:

$("#form_holder").html("<%= escape_javascript(render(:partial => "leads_field"))%>");

我想只渲染那部分(如果我渲染整个表单,那么他们所有的联系信息都将被删除。)。但由于该部分包含一个局部f变量,它会爆炸:

NameError - undefined local variable or method `f'

我想维护对象之间的关系,但也只更新那个部分。但似乎我不能通过new.js.erb脚本来实现它,因为当它呈现部分时,没有传递局部变量'f'。

还有另一种方法可以达到我的目的吗?

1 个答案:

答案 0 :(得分:0)

我发现这个问题很难在两个方面解决。首先,您无法从控制器操作和javascript中识别表单构建器。其次,尽管我对railscasts剧集http://railscasts.com/episodes/196-nested-model-form-revised?view=comments非常熟悉,但在那一集中他知道fields_for在编译时生成,因此他将标记隐藏在链接的数据字段中。不幸的是,在我的情况下,我不知道用户想要的fields_for直到运行时(当浏览器加载并且用户选择一个选项时)。

我还意识到fields_for对于保持表单提交的良好关联很重要,这样创建操作就可以了:保存父资源并保存其关联。

我能想出的最佳解决方案如下:

1)使用fields_for创建所有多态关联,并通过选择表单字段隐藏用户不想要的关联:

# template
<div id="runtime-profile">
    <% Lead::TYPES.each_with_index do |association, index| %>
      <div id="profile_<%= association %>">
        <fieldset class="field-border">
          <legend class="field-border"><%= association.underscore %></legend>
            <%= f.fields_for :practice, build_builder_association(f, association) do |builder| %>
              <%= render "#{builder.object.class.name.underscore}_field", :f => builder %>
            <% end %>
      </div>
    <% end %>
  </div>

# helper
def build_builder_association(f, association)
  f.object.practice_type = association
  f.object.build_practice({})
end

使用Javascript根据从下拉列表中选择的选项隐藏和显示模板,然后在提交表单时,从DOM中删除隐藏的元素:

    $("#new_lead").submit(function(){
        $("[id^='profile_']:hidden").remove();
    })

这创造了我想要的原始所需行为。但是,解决方案远非干净,欢迎任何更好的建议。