1

I have a parent which has multiple children. I want it so that when I submit my form, a parent is generated in the parent model, and multiple records are created in the child model, one for each child. When I try and submit, I get the following error:

 ActiveRecord::AssociationTypeMismatch in ParentsController#create

   Child(#) expected, got Array(#)

When I uncomment accepts_nested_attributes_for :children and change f.fields_for :children to f.fields_for :children_attributes, I get a different error:

  TypeError in ParentsController#create

    can't convert Symbol into Integer

I am at a loss as to what to do. I have checked out the nested model forms railscasts, but they were dealing with generating children fields inside the form, and what I learned from the railscasts didn't seem to work. I am pretty I am doing my builder.text_field :cname's in my form wrong, but I'm not aware of the proper way to do it.

My code:

parent.rb

class Parent < ActiveRecord::Base
  has_many :children
  #accepts_nested_attributes_for :children
  attr_protected :id

child.rb

class Child < ActiveRecord::Base
  belongs_to :parent
  attr_protected :id

_form.html.erb

<%= form_for @parent, :url => { :action => "create" } do |f| %>
  <%= f.text_field :pname %>
  <%= f.fields_for :children do |builder| %>
    <%= builder.text_field :cname %>
    <%= builder.text_field :cname %>
    <%= builder.text_field :cname %>
  <% end %>
  <%= f.submit %>
<% end %>

params content:

{"utf8"=>"✓",
 "authenticity_token"=>"FQQ1KdNnxLXolfes9IGiO+aKHJaPCH+2ltDdA0TwF7w=",
 "parent"=>{"pname"=>"Heman",
 "child"=>{"cname"=>""}},
 "commit"=>"Create"}
MrYoshiji
  • 54,334
  • 13
  • 124
  • 117
notblakeshelton
  • 364
  • 1
  • 7
  • 20
  • Can you post the `params` containing the attributes for children, when you submit the form, please? I'm pretty sure you just have to loop on the `params[:children]` since your error log tells us it is an Array – MrYoshiji Jul 03 '13 at 17:51
  • @MrYoshiji you might come to my rescue yet again. I have updated my question with the params. Only one child appears and it doesn't display any names. – notblakeshelton Jul 03 '13 at 18:06
  • 1
    Ah, I recognize this... Give me a minute, I post an answer, while you can take a look at this very similar issue: http://stackoverflow.com/questions/16919711/multiple-non-nested-model-creation-on-same-page/16920211#16920211 – MrYoshiji Jul 03 '13 at 18:08

1 Answers1

4

The problem here is that the generated form in HTML for the children are using the same "place" (same pair key/value) in the params Hash (using the params[:parent][:child][:cname] pair). This is why there is only one param 'name' in the 'child' node in the Params hash.

To avoid that, you can use an array for the input's name:

<input type="text" name="child[][cname]" />
<input type="text" name="child[][cname]" />

The params, when this submitted, will look like this:

params: {
  child: [ { cname: 'blabla' }, { cname: 'bonjour' } ]
}

To get the desired result, in your case:

<%= form_for @parent, :url => { :action => "create" } do |f| %>
  <%= f.text_field :pname %>

  <%= text_field_tag "parent[children][][cname]" %>
  <%= text_field_tag "parent[children][][cname]" %>
  <%= text_field_tag "parent[children][][cname]" %>

  <%= f.submit %>
<% end %>

Should produce something like this:

{
  "utf8"=>"✓",
  "authenticity_token"=>"FQQ1KdNnxLXolfes9IGiO+aKHJaPCH+2ltDdA0TwF7w=",
  "parent"=> { 
    "pname"=>"Heman",
    "children"=> [
      { "cname"=>"SisiSenior" },
      { "cname"=>"Bonjor" },
      { "cname"=>"Blabla" }
    ]
  },
  "commit"=>"Create"}

So in your controller, you could use something like this:

#ParentsController
def create
  children_attributes = params[:parent].delete(:children) # takes off the attributes of the children
  @parent = Parent.create(params[:parent])

  children_attributes.each do |child_attributes|
    child = @parent.children.create(child_attributes)
  end
end
MrYoshiji
  • 54,334
  • 13
  • 124
  • 117
  • 1
    holy buckets mate. you're a life saver. Thanketh so mucheth. And of course, may your sword stay sharp and your steed be quick. – notblakeshelton Jul 03 '13 at 19:53
  • sorry about this but i figured it was too simple to be a new question. is there a way to make it to only create the record if name isnt blank? I figured it would work to just use an if #something != nil child=@parent.children.create(child_attributes) end, but I don't know what to put instead of #something. – notblakeshelton Jul 03 '13 at 21:55
  • 1
    nevermind i figured it out. i replaced #something != nil with child_attributes["name"] != "" – notblakeshelton Jul 03 '13 at 22:40