Reputation: 301
In my app, I have Contacts, which have many Goals (Goals belong to Contact). I use a nested form to create/update data for both models, however only the first child Goal gets saved during create/update actions, which can be seen from the parameters being passed below:
Started PATCH "/contacts/2" for 127.0.0.1 at 2014-05-11 19:10:40 -0400
Processing by ContactsController#update as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"wKgOPegIJOFyrrLAnbdD67qqATFXrPNqMIT7I/tpNfo=", "contact"=>{"name"=>"Steven Tyler", "title"=>"Manager", "company"=>"Dell", "email"=>"[email protected]", "notes"=>"cool guy", "goals_attributes"=>{"0"=>{"title"=>"goal1", "due_date(1i)"=>"2014", "due_date(2i)"=>"5", "due_date(3i)"=>"11", "notes"=>"fdfsd", "_destroy"=>"false", "id"=>"13"}}}, "commit"=>"submit", "id"=>"2"}
Contact Load (0.1ms) SELECT "contacts".* FROM "contacts" WHERE "contacts"."id" = ? LIMIT 1 [["id", 2]]
(0.1ms) begin transaction
Goal Load (0.3ms) SELECT "goals".* FROM "goals" WHERE "goals"."contact_id" = ? AND "goals"."id" IN (13) [["contact_id", 2]]
(0.1ms) commit transaction
Redirected to http://localhost:3000/contacts/2
Here are my Models:
class Contact < ActiveRecord::Base
belongs_to :user
has_many :goals, dependent: :destroy
accepts_nested_attributes_for :goals, allow_destroy: true, reject_if: lambda {|attributes| attributes['title'].blank? && attributes['notes'].blank?}
validates_presence_of :user_id,:name,:title,:email
end
class Goal < ActiveRecord::Base
belongs_to :contact
validates_presence_of :title, :due_date
end
And, strong parameters in the Contacts controller:
def contact_params
params.require(:contact).permit(:name, :title, :company, :email, :notes, goals_attributes: [:title, :due_date, :notes, :contact_id, :_destroy, :id])
end
Here are the two forms used: https://gist.github.com/nowgeez/5fbe99e814330c1b371c Any idea why only the first Goal is being saved and not any other subsequent goals created in the form? Thanks in advance for the help.
Upvotes: 2
Views: 1286
Reputation: 50057
As stated in the documentation, it is important to use the correct nesting of divs.
So in your case you should write:
<%= simple_form_for(@contact) do |f| %>
<%= f.input :name %>
<%= f.input :title %>
<%= f.input :company %>
<%= f.input :email %>
<%= f.input :notes %>
<h3>Goals:</h3>
<div id="goals">
<%= f.simple_fields_for(:goals) do |goal| %>
<%= render 'goal_fields', :f => goal %>
<% end %>
<div class="links">
<%= link_to_add_association 'add goal', f, :goals %>
</div>
</div>
<%= f.submit :submit %>
<% end %>
For clarity I have removed the error-block. The goals themselves should be wrapped in a div, for the remove to work.
<div class="nested-fields>
<%= f.input :title %>
<%= f.input :due_date %>
<%= f.input :notes %>
<%= link_to_remove_association "remove goal", f %>
</div>
On a side-note: I hate to write erb, it is much more verbose, and from your gist it seems properly nested, but it actually is not. Haml is imho much clearer. Just to prove my point, the same as the above form in haml looks like:
= simple_form_for @contact do |f|
= f.input :name
= f.input :title
= f.input :company
= f.input :email
= f.input :notes
%h3 Goals
#goals
= f.simple_fields_for :goals do |goal|
= render 'goal_fields', :f => goal
.links
= link_to_add_association 'add goal', f, :goals
= f.submit
But I understand it is a matter of taste.
Upvotes: 3
Reputation: 1812
In your request there is only one goal
"goals_attributes"=>{"0"=>{"title"=>"goal1", "due_date(1i)"=>"2014", "due_date(2i)"=>"5", "due_date(3i)"=>"11", "notes"=>"fdfsd", "_destroy"=>"false", "id"=>"13"}}}
I guess you are doing something wrong with strong parameters, change it to something like this:
def contact_params
params.require(:contact)
.permit(:name, :title, :email, :company, :notes,
goal_attributes: [:title, :due_date, :notes, :_destroy, :id])
end
Upvotes: 0