I'm using Rails and the Wicked Gem to create a multi-step form. I have a Parent and a Child model. Parents have many children, and the parents form accepts_nested_attributes_for :children.
I'm building a nested object on the SHOW action of the controller so that a form field displays.
For some reason, every time the form is saved the number of children in the database (and the number of form fields on the view) are doubled. First it will save 1 child as expected. Then if I go back to update that part of the form and save that child, it creates 2 children, then 4, etc.
Here is the relevant code:
parent.rb
class Parent < ApplicationRecord
belongs_to :user
has_many :children
accepts_nested_attributes_for :children
end
child.rb
class Child < ApplicationRecord
belongs_to :parent
end
parent_steps_controller.rb
class ParentStepsController < ApplicationController
include Wicked::Wizard
steps :spouse, :children
def show
@user = current_user
if Parent.find_by(id: params[:parent_id])
@parent = Parent.find(params[:parent_id])
session[:current_parent_id] = @parent.id
else
@parent = Parent.find_by(id: session[:current_parent_id])
end
@parent.children.build
render_wizard
end
def update
@parent = Parent.find_by(id: session[:current_parent_id])
@parent.update_attributes(parent_params)
render_wizard @parent
end
private
def parent_params
params.require(:parent).permit(:spouse_name, :children_attributes => [:full_name])
end
end
children.html.erb
<%= form_for(@parent, :url=> wizard_path, :method => :put) do |f| %>
<h1>Children Information</h1>
<%= f.fields_for :children do |child| %>
<div class="field">
<%= child.label :full_name %>
<%= child.text_field :full_name %>
</div>
<% end %>
<%= f.submit "Continue", :class => "btn btn-primary" %>
<% end %>
You need to add the child.id
to the set returned. If rails doesn't see an ID, it assumes these are new records. It doesn't have to be visible to you, but must be part of the form.
<%= f.fields_for :children do |child| %>
<%= child.hidden_field :id %>
Also ensure your strong parameters allow :id
to be passed through for the children_attributes
part.
def parent_params
params.require(:parent).permit(:spouse_name, :children_attributes => [:id, :full_name])
end