Question

Problem

After some success creating nested models from a form in Rails 4 (with the help of the Cocoon gem), I am now trying to stretch a little further - to editing those nested models after they've been created.

When I attempt to update for a parent with two children - no actual changes have been made in the form, it's just been loaded and then saved straight away again - the update is not successful, I have a validation error, and the children in the newly render edit form look incorrect.

Markup

<%= form_for @parent do |f| %>
  <%= f.fields_for :children do |builder| %>
    <%= builder.label :some_property %>  
    <%= builder.text_field :some_property %>      
    <%= builder.label :some_other_property %>  
    <%= builder.text_field :some_other_property %>      
  <% end %>
<% end %>

Controller action

def update
  @parent = Parent.find(params[:id])
  if (@parent.update(parent_params))
    redirect_to somewhere
  else
    flash.now[:error] = "Oops, this didn't work."
    render 'edit'
  end
end

def parents_params        
  params.require(:parent).
    permit(:id, child_attributes: [:id, :some_property, :some_other_property, :_destroy])
end 

Parameters being passed to the controller

--- !ruby/hash:ActionController::Parameters
utf8: ✓
_method: patch
authenticity_token: // blah
parent: !ruby/hash:ActionController::Parameters
  children_attributes: !ruby/hash:ActionController::Parameters
    '0': !ruby/hash:ActiveSupport::HashWithIndifferentAccess
      some_property: FOO
      some_other_property: 46
      _destroy: 'false'
      id: '8'
    '1': !ruby/hash:ActiveSupport::HashWithIndifferentAccess
      some_property: BAR
      some_other_property: 25
      _destroy: 'false'
      id: '9'
commit: Save
action: update
controller: parents
id: '3'

Validation failure

This validation fails, and the child is claimed to not be unique.

# from child.rb
validates :some_property, uniqueness: true

Summary

This form works fine when saving the first children - even multiple children - it's when revisiting the page and trying to save again that the problem arises.

Note that when the form is rendered the second tme (after the failed save), it now contains details for the second child, twice over (i.e. BAR/25) as the only two children.

(I've considered some workarounds - switching to a specific model to cover the nested model and then mapping it back, for example - but I'd like to get to the bottom of why this isn't behaving as I want to improve my knowledge of the rails internals.)

Thanks for any help in advance!

Was it helpful?

Solution

I found the solution (after adding some debugging code in desperation and seeing my test suddenly pass!).

For some reason, in the controller, loading the parent did not also load the existing children fully, so the new children were being incorrectly recognised.

Changing the controller code to this:

def update
  # This is the key line - note the additional .includes
  @parent = Parent.includes(:children).find(params[:id])

  if (@parent.update(parent_params))
  ...
end

Solved the problem.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top