Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Rails 4 - saving object with nested attributes

I have a parent model that has one child model with nested attributes. I have a single form that updates both parent and child.

Here are my models:

class Parent < ActiveRecord::Base
  has_one :child
  accepts_nested_attributes_for :child
end

class Child < ActiveRecord::Base
  belongs_to :parent
end

Form view:

<%= form_for @parent, do |f| %>
  <%= f.text_field :parent_name %>
  <%= f.fields_for @parent.child do |c| %>
    <%= c.text_field :child_name %>
  <% end %>
  <%= f.submit "Save" %>
<% end %>

Parent controller:

class ParentsController < ApplicationController      
  def update
    @parent = Parent.find(params[:id])    
    @parent.update(params.require(:parent).permit(:parent_name, child_attributes: [:child_name]))

    redirect_to @parent
  end
end

When I save the form, the parent updates but the child doesn't. What am I doing wrong?

like image 697
FloorLamp Avatar asked Feb 15 '23 21:02

FloorLamp


2 Answers

You have a problem in the nested part of your form code, it should be

<%= form_for @parent, do |f| %>
  <%= f.text_field :parent_name %>
  <%= f.fields_for :child do |c| %>  <<<<<<<<<<< this line was wrong
    <%= c.text_field :child_name %>
  <% end %>
  <%= f.submit "Save" %>
<% end %>

You have to pass the id in the params attributes too :

@parent.update(params.require(:parent).permit(:parent_name, child_attributes: [:id, :child_name]))

Cheers

like image 125
phron Avatar answered May 18 '23 15:05

phron


In your controller

class ParentsController < ApplicationController      
  def edit
    @parent = Parent.find(params[:id])
    @child = @parent.child.build
  end
end

In your view

<%= form_for @parent, do |f| %>
  <%= f.text_field :name %>
  <%= f.fields_for @child do |builder| %>
    <%= builder.text_field :name %>
  <% end %>
  <%= f.submit "Save" %>
<% end %>

Assuming parent_name and child_name was here to illustrate your need. Your attributes should not be name-spaced like this.

You also have to pass the id in the permit method like this

child_attributes: [:id, :name]

Or using child_name

child_attributes: [:id, :child_name]

This is not well documented at this time.

like image 26
Pierre-Louis Gottfrois Avatar answered May 18 '23 15:05

Pierre-Louis Gottfrois