问题
I am trying to build a form with nested resources in my rails 4 app. I am using the cocoon gem. Each step will have substeps, and I'd like to allow the user to add as many substeps to the form and he/she would like.
Step.rb
class Step < ActiveRecord::Base
has_many :substeps
accepts_nested_attributes_for :substeps
Substep.rb
class Substep < ActiveRecord::Base
belongs_to :step
form code
<%= form_for Step.new, :url => steps_path do |f| %>
<%= text_field(:step, :title, :value => '', class: 'fly-input input_info', placeholder: 'Process Title', id: 'step_form_title') %>
<%= text_field(:step, :description, :value => '', class: 'fly-input input_info', placeholder: 'Process Description', id: 'step_form_description') %>
<%= hidden_field :step, :known %>
<%= hidden_field_tag :experiment, @experiment.id %>
<%= f.fields_for :substep do |ff| %>
<%= render "substep_fields", :f => ff %>
<% end %>
<%= link_to_add_association 'Add substep', f, :substeps %>
<%= f.submit "Done", class: "main_button" %>
<% end %>
_substep_fields.html.erb
<div class='nested-fields'>
<%= f.text_field :description %>
</div>
steps_controller.rb
def step_params
params.require(:step).permit(:title, :description, :known, substeps_attributes: [:id, :description, :action, :_destroy])
end
I can see the first input, and add second, third, so on inputs for multiple substeps. The problem is, only the first substep's description will be passed to the controller:
(byebug) params
params
{"utf8"=>"✓", "authenticity_token"=>"xxx", "step"=>{"title"=>"Test Title", "description"=>"Test Desc", "known"=>"-1", "substep"=>{"description"=>"Substep1"}}, "experiment"=>"64", "commit"=>"Done", "controller"=>"steps", "action"=>"create"}
Any thoughts on my problem?
EDIT Sharing HTML generated after adding two substeps
<form class="new_step" id="new_step" action="/steps" accept-charset="UTF-8" method="post">
<input name="utf8" type="hidden" value="✓"><input type="hidden" name="authenticity_token" value="xxxx">
<input value="" class="fly-input input_info ui-autocomplete-input" placeholder="Process Title" id="step_form_title" type="text" name="step[title]" data-hasqtip="6" aria-describedby="qtip-6" autocomplete="off">
<label class="fly-label classic is-active" for="classic">Description</label>
<input value="" class="fly-input input_info" placeholder="Process Description" id="step_form_description" type="text" name="step[description]" data-hasqtip="7" aria-describedby="qtip-7">
<input type="hidden" name="step[known]" id="step_known" value="-1">
<input type="hidden" name="experiment" id="experiment" value="76">
</form>
<div class="nested-fields">
<input type="text" name="step[substeps_attributes][1453146839656][description]" id="step_substeps_attributes_1453146839656_description">
</div>
<div class="nested-fields">
<input type="text" name="step[substeps_attributes][1453146844032][description]" id="step_substeps_attributes_1453146844032_description">
</div>
<div class="" id="customprocess_processsteps">
<a class="main_button add_fields" data-association="substep" data-associations="substeps" data-association-insertion-template="<div class='nested-fields'>
<input type="text" name="step[substeps_attributes][new_substeps][description]" id="step_substeps_attributes_new_substeps_description" />
</div>" href="#">Add substeps</a>
<button aria-label="Close reveal" class="close-button" data-close="" type="button">
</button>
</div>
<input type="submit" name="commit" value="Done" class="main_button">
回答1:
You need to match exactly the name of the association within fields_for
. Change this:
<%= f.fields_for :substep do |ff| %>
To
<%= f.fields_for :substeps do |ff| %>
EDIT: Cocoon expects a strict DOM structure to work, try changing
<%= f.fields_for :substep do |ff| %>
<%= render "substep_fields", :f => ff %>
<% end %>
<%= link_to_add_association 'Add substep', f, :substeps %>
To:
<div id="substeps">
<%= f.fields_for :substep do |ff| %>
<%= render "substep_fields", :f => ff %>
<% end %>
<div class="links">
<%= link_to_add_association 'Add substep', f, :substeps %>
</div>
</div>
If I remember correctly, only wrapper around link_to_add_association
is required, the most top-level wrapper is just nice to have.
回答2:
There are two changes you need to make. One is as BroiSatse wrote, changing
<%= f.fields_for :substep do |ff| %>
to
<%= f.fields_for :substeps do |ff| %>
and second, changing
params.require(:step).permit(..., substeps_attributes: [:id, :description, :action, :_destroy])
to
params.require(:step).permit(..., substeps_attributes: [[:id, :description, :action, :_destroy]])
来源:https://stackoverflow.com/questions/34859649/rails-cocoon-nested-form-only-receiving-one-first-nested-attribute