Topic: creating children with parent

Right now I have a parent class, which has_many :children. When I create the parent, I want to create the children at the same time, because in my application, the parent is meaningless without children.

I want a form something like this:

Parent Name: _________
Parent DOB: _________

   ===========================
*  = Child Name ____________ = X (Delete)
   = Child DOB _____________ =
   ===========================
   
   ===========================
*  = Child Name ____________ = X (Delete)
   = Child DOB _____________ =
   ===========================

Add A Child

Save


Any idea how to do this?

Thanks a lot!

P.S. You can get Rails Weenie points for this if you get the answer: http://rails.techno-weenie.net/question … ith-parent

Re: creating children with parent

My first reaction is to have you look at acts_as_tree for your relationship. Rather than a Parent & Child class you'd have a Person class.

Here would be your view:

<%= form_tag :action => 'create' %>
<fieldset>
  <legend>Parent Info</legend>
  <ol>
    <li><label for="parent_name">Name:</label>
      <%= text_field "parent", "name" %>
    </li>
    <li><label for="parent_dob">DOB:</label>
      <%= date_select "parent", "dob" %>
    </li>
  </ol>
</fieldset>
<fieldset>
  <legend>Child</legend>
    <ol>
      <li><label for="child_name">Name:</label>
        <%= text_field "child", "name" %>
      </li>
      <li><label for="child_dob">DOB:</label>
        <%= date_select "child", "dob" %>
      </li>
    </ol>
</fieldset>
<%= submit_tag "Add Family" %>
<%= end_form_tag %>

Here is your controller (excerpt):
acts_as_tree
def create
  @parent = Person.create(params[:parent])
  @child = @parent.children.create(params[:child])
end

You'd need to be sure you have a "parent_id" column in your database for this to work.

Last edited by Reedy (2006-07-28 13:51:21)

Most code examples are usually pulled out of the air and not tested. Use at your own risk!

Re: creating children with parent

I'll be posting this to rails.techno-weenie.com when it is back up, but right now I'm getting 503's so it's going here first.

So, my previous reply missed a few points. Here is the basic questions in two parts:

1) How do you handle creating a "parent" object and "child" objects within the same form
and
2) How do you pass an array from a form into a controller.

Answer to question 1:
This is easy, just create the parent first and then use that ID for the children.

def create 
  @parent = Parent.create(params[:parent])
  for child in params[:children]
    @child = Child.new(child[1])
    @child.parent = @parent
    @child.save
  end
end

The above code assumes you are using a form that is passing an array through the form. This is a subject that I have had success in doing, but I'm not sure if there is a more "rails-esque" way of handling it. This has worked for me though. This leads us to question number two, passing the array.

Here is the form:

<%= start_form :action => 'create' %>
  <fieldset>
    <legend>Parent</legend>
    <ol>
      <li><label for="parent_name">Parent:</label>
        <%= text_field :parent, :name %>
      </li>
      <li><label for="parent_dob">DOB:</label>
        <%= date_select :parent, :dob %>
      </li>
    </ol>
    <fieldset>
      <legend>Children</legend>
      <ol id="children">
        <%= render :partial => 'child_fields' %>
      </ol>
      <p><%= link_to_remote 'Add a Child', :url => { :action => 'add_child_fields' } %></p>
    </fieldset>
  </fieldset>
  <p><%= submit_tag 'Save' %></p>
<%= end_form_tag %>

This includes a couple of things we need to look closer at, first being the partial that is rendered. That code follows:

<li><label>Name:</label>
  <%= text_field_tag "children[#{session[:child_count]}][name]" %></li>
<li><label>Favorite Pet:</label>
  <%= text_field_tag "children[#{session[:child_count]}][favorite_pet]" %></li>
<% session[:child_count] += 1 -%>

We see a little more going on here with session variables to help us manage the array. The reason being that children[][name] does not work but children[0][name] does work. Let's look at the controller:

def index
  session[:child_count] ||= 0
end

def create
   @parent = Parent.create(params[:parent])
  for child in params[:children]
    @child = Child.new(child[1]) # notice it is child[1] and not just child
    @child.parent = @parent
    @child.save
  end
  # reset our child count
  session[:child_count] = 0
end


This is a very basic look at this situtation. Hopefully this will work as I've done some limited testing on it. I'm also not reproducing the RJS template to add the extra field, but if you look at the previous post you'll see it up there.

Most code examples are usually pulled out of the air and not tested. Use at your own risk!