Rails 4 Update Nested Attributes

You need to edit you params with pets_attributes

Also need to add :id paramter in the pet objects.


You have to add the :id attribute to the :pets_attributes array in person_params.

You need to permit the id attribute to update the records.


see the manual:

http://api.rubyonrails.org/v4.0.1/classes/ActiveRecord/NestedAttributes/ClassMethods.html

you need to send in your attributes like pets_attributes:[{name:'jeffy', type:'dog'}, {name:'sharky', type:'fish'}]

and it should work fine.

Please read

You can now set or update attributes on the associated posts through an attribute hash for a member: include the key :posts_attributes with an array of hashes of post attributes as a value.For each hash that does not have an id key a new record will be instantiated, unless the hash also contains a _destroy key that evaluates to true.


Update the Person model as below:

class Person < ActiveRecord::Base  ## NOTE: class (c lowercase) and NOT Class
 has_many :pets
 accepts_nested_attributes_for :pets, allow_destroy: true  ## Added allow_destroy
end

In order to destroy the associated model i.e., Pet through the attributes hash, you have to enable it first using the :allow_destroy option.

Then, from your view, you will need to pass the _destroy attribute for the pets that you would like to be removed.

Since, you haven't shared the view specific code. Following is an example of how it should be implemented in your view. Change it according to your requirement:

<%= form_for @person do |f| %>
  <%## .. %>  
  <%= f.fields_for :pets do |builder| %>
    <%## .. %>    
    <%= builder.check_box :_destroy %>
    <%= builder.label :_destroy, "Remove Pet" %>
  <% end %>
<% end %>

In the above code, you would need to add the checkbox and label for passing _destroy value.

After this, update the person_params method in your controller as below:

def person_params
  params.require(:person).permit(:house_no, pets_attributes: [:id, :name, :type, :person_id, :_destroy])
end 

NOTE:

You should not be defining instance variables with capitalized name. Capitalized names are used for declaring Constants in Ruby.

def update
  @person = Person.find(params[:id])
  if @person.update(person_params)
    @person.save
    render 'persons/create', status 200
  else
    render 'persons/create', status 400
  end
end