Reputation: 3522
I have a rails 4 app that has a form that looks like:
<%= 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 %>
and the edit_product_fields partial looks like:
<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>
When I have the code like this, I get the error:
undefined method `type_of' for #<NestedForm::Builder:0x00000102304f78>
but if I change the render line to (I just made it less explicit by taking out partial:):
<%= render "edit_product_fields", locals: {product:product} %>
I get the error:
undefined local variable or method `product' for #<#<Class:0x0000010235a248>:0x0000010684b3c0>
Upvotes: 0
Views: 44
Reputation: 18037
Well type_of
is not a ruby method. It looks like it's an attempt to type check though... But type checking is generally frowned upon in duck-typed languages. At any rate, we can take advantage of a Rails Form Helper instead and make this code a one-liner. But first...
The reason the render
is complaining about undefined local variable or method
product'` after your change is because the render call expects either the first argument to be a partial name and the second to be a hash of locals:
<%= render "partial_name", local1: "a", local2: "b" %>
... or it expects the the whole thing to be a hash:
<%= render partial: "partial_name", locals: { local1: "a", local2: "b" } %>
Now, back to the form helper.
What you're looking for here is the select helper. This makes the following possible:
<%= product.select :type_of, %w[Textbook Magazine Book] %>
And this will render all of the same html as you've put into your _edit_product_field.html.erb
partial. So you should probably just get rid of the partial to save on rendering time and put this directly into your form.
One other, minor point. It may be less confusing to call the fields_for
block variable product_form
instead of product
. This is to help keep in mind that this is not a Product object you're dealing with, but rather a Form Generator object. Also, you don't need to specify :multipart => true
in Rails 4 forms -- Rails knows to make the form multi-part if you have a file upload element within the form body.
So putting it all together:
<%= form_for @store do |f| %>
<%= f.fields_for :products do |product_form| %>
<%= product_form.select :product, %w[Textbook Magazine Book] %>
<% end %>
<%= f.submit %>
<% end %>
Upvotes: 2
Reputation: 18090
In your first code block, you have a Builder
object being stored as product
.
Fortunately, Builder
provides an object
method so you can access the actual object that it's representing in the form:
<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>
Upvotes: 2