Problem using form builder & DOM manipulation in Rails with multiple levels of nested partials
- by Chris Hart
I'm having a problem using nested partials with dynamic form builder code (from the "complex form example" code on github) in Rails. I have my top level view "new" (where I attempt to generate the template):
<% form_for (@transaction_group) do |txngroup_form| %>
<%= txngroup_form.error_messages %>
<% content_for :jstemplates do -%>
<%= "var transaction='#{generate_template(txngroup_form, :transactions)}'" %>
<% end -%>
<%= render :partial => 'transaction_group', :locals => { :f => txngroup_form, :txn_group => @transaction_group }%>
<% end -%>
This renders the transaction_group partial:
<div class="content">
<% logger.debug "in partial, class name = " + txn_group.class.name %>
<% f.fields_for txn_group.transactions do |txn_form| %>
<table id="transactions" class="form">
<tr class="header"><td>Price</td><td>Quantity</td></tr>
<%= render :partial => 'transaction', :locals => { :tf => txn_form } %>
</table>
<% end %>
<div> </div><div id="container">
<%= link_to 'Add a transaction', '#transaction', :class => "add_nested_item", :rel => "transactions" %>
</div>
<div> </div>
... which in turn renders the transaction partial:
<tr><td><%= tf.text_field :price, :size => 5 %></td>
<td><%= tf.text_field :quantity, :size => 2 %></td></tr>
The generate_template code looks like this:
def generate_html(form_builder, method, options = {})
options[:object] ||= form_builder.object.class.reflect_on_association(method).klass.new
options[:partial] ||= method.to_s.singularize
options[:form_builder_local] ||= :f
form_builder.fields_for(method, options[:object], :child_index => 'NEW_RECORD') do |f|
render(:partial => options[:partial], :locals => { options[:form_builder_local] => f })
end
end
def generate_template(form_builder, method, options = {})
escape_javascript generate_html(form_builder, method, options)
end
(Obviously my code is not the most elegant - I was trying to get this nested partial thing worked out first.)
My problem is that I get an undefined variable exception from the transaction partial when loading the view:
/Users/chris/dev/ss/app/views/transaction_groups/_transaction.html.erb:2:in
_run_erb_app47views47transaction_groups47_transaction46html46erb_locals_f_object_transaction'
/Users/chris/dev/ss/app/helpers/customers_helper.rb:29:in
generate_html'
/Users/chris/dev/ss/app/helpers/customers_helper.rb:28:in
generate_html'
/Users/chris/dev/ss/app/helpers/customers_helper.rb:34:in
generate_template'
/Users/chris/dev/ss/app/views/transaction_groups/new.html.erb:4:in
_run_erb_app47views47transaction_groups47new46html46erb'
/Users/chris/dev/ss/app/views/transaction_groups/new.html.erb:3:in
_run_erb_app47views47transaction_groups47new46html46erb'
/Users/chris/dev/ss/app/views/transaction_groups/new.html.erb:1:in
_run_erb_app47views47transaction_groups47new46html46erb'
/Users/chris/dev/ss/app/controllers/transaction_groups_controller.rb:17:in
new'
I'm pretty sure this is because the do loop for form_for hasn't executed yet (?)... I'm not sure that my approach to this problem is the best, but I haven't been able to find a better solution for dynamically adding form partials to the DOM. Basically I need a way to add records to a has_many model dynamically on a nested form.
Any recommendations on a way to fix this particular problem or (even better!) a cleaner solution are appreciated. Thanks in advance.
Chris