嵌套表单呈现问题

时间:2014-05-30 00:05:24

标签: html ruby-on-rails ruby forms

我有一个rails 4应用程序,其形式如下:

<%= form_for @store, :html => {:multipart => true} do |f| %>
  <%= f.fields_for :products do |product| %>
    <%= render partial: "edit_product_fields", locals: {product:product} %>
  <% end %>
  <%= f.submit %>
<% end %>

和edit_product_fields部分看起来像:

<select>
   <option value="Textbook" <% if product.type_of == "Textbook" %>selected<% end %>>Textbook</option>
   <option value="Magazine" <% if product.type_of == "Magazine" %>selected<% end %>>Magazine</option>
   <option value="Book"     <% if product.type_of == "Book"     %>selected<% end %>>Book</option>
</select>

当我有这样的代码时,我收到错误:

undefined method `type_of' for #<NestedForm::Builder:0x00000102304f78>

但如果我将渲染线更改为(我只是通过取出 partial:使其不那么明确):

<%= render "edit_product_fields", locals: {product:product} %>

我收到错误:

undefined local variable or method `product' for #<#<Class:0x0000010235a248>:0x0000010684b3c0>

2 个答案:

答案 0 :(得分:2)

在您的第一个代码块中,您将Builder对象存储为product

幸运的是,Builder提供了object方法,因此您可以访问它在表单中表示的实际对象:

<select>
   <option value="Textbook" <%= 'selected' if product.object.type_of == "Textbook" %>>Textbook</option>
   <option value="Magazine" <%= 'selected' if product.object.type_of == "Magazine" %>>Magazine</option>
   <option value="Book"     <%= 'selected' if product.object.type_of == "Book"     %>>Book</option>
</select>

答案 1 :(得分:2)

type_of不是ruby方法。它看起来像是尝试键入检查...但是类型检查通常不会被鸭子类型的语言所禁止。无论如何,我们可以利用Rails Form Helper来代替这个代码。但首先......

更改后render抱怨undefined local variable or method product'的原因是因为渲染调用要求第一个参数是部分名称,第二个参数是本地的哈希值:

<%= render "partial_name", local1: "a", local2: "b" %>

...或者它希望整个事情都是哈希:

<%= render partial: "partial_name", locals: { local1: "a", local2: "b" } %>

现在,回到表单助手。

您在这里寻找的是select帮手。这使得以下成为可能:

<%= product.select :type_of, %w[Textbook Magazine Book] %>

这将呈现与您放入_edit_product_field.html.erb部分相同的html。因此,您可能只需要删除部分以节省渲染时间并将其直接放入表单中。

另一个,小问题。调用fields_for块变量product_form而不是product可能不那么令人困惑。这是为了帮助记住,这不是您正在处理的Product对象,而是Form Generator对象。此外,您不需要在Rails 4表单中指定:multipart => true - 如果您在表单正文中有文件上传元素,则Rails知道如何使表单成为多部分。

所以把它们放在一起:

<%= form_for @store do |f| %>
  <%= f.fields_for :products do |product_form| %>
    <%= product_form.select :product, %w[Textbook Magazine Book] %>
  <% end %>
  <%= f.submit %>
<% end %>