Forum: Ruby on Rails has_many: inserting children when inserting parent

Announcement (2017-05-07): www.ruby-forum.com is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see rubyonrails.org/community and ruby-lang.org/en/community for other Rails- und Ruby-related community platforms.
E34331b0673de4add7fd825a0848cc04?d=identicon&s=25 Evan Haveman (emh)
on 2006-02-23 07:28
disclaimer: am in the midst of my first ruby/rails project

I have a situation where I want several child records to be created when
a new parent record is created. The following represents my first stab
at coding it, am I on the right track?

Here is the model:

parents
----------
id
name

children
----------
id
parent_id
name

class Parent < ActiveRecord::Base
  has_many: children
end

class Child < ActiveRecord::Base
  belongs_to: child
end

the rhtml form has two text fields, one for a parent's name and one for
a space delimited list of childrens' names.

<%= text_field 'parent', 'name' %>
<%= text_field 'childlist', 'names' %>

Now the ParentController and its create method which I would like to
save both the parent and all its childeren:

class ParentsController < ApplicationController
  def create
    @parent = Parent.new(params[:parent])
    @parent.save

    childnames = params[:childlist][:names]
    childname.split(/\s+/).each do |name|
      child = Child.new({ :parent_id => @parent.id, :name => name})
      child.save
      @parent.children << child
    end

    redirect_to :action => 'list'
end

Is this the right approach? Are there any ruby-isms or rails-ims I am
not picking up on?
7be5946d882f1df9916c005310dc78b4?d=identicon&s=25 Jonas Nicklas (coward)
on 2006-02-23 09:52
Basically it's all good, however, you can place the call to @parent.save
after adding all the children, the advantage of this is than error
thrown before save will not result in a lonely parent. Also I *think*
Rails wraps the statements in a transaction if you do this, meaning that
nothing will be saved if anything goes wrong. Also, the child.save is
unneccessary in this case. (Oh and so is the local variable, and passing
parent_id :)

Like this:

class ParentsController < ApplicationController
   def create
     @parent = Parent.new(params[:parent])

     params[:childlist][:names].split(/\s+/).each do |name|
       @parent.children << Child.new({ :name => name })
     end

     @parent.save

     redirect_to :action => 'list'
end
E34331b0673de4add7fd825a0848cc04?d=identicon&s=25 Evan Haveman (emh)
on 2006-02-25 11:29
Wow thanks, I'm liking rails more and more. The behind the scene stuff
tho like setting the parent id automatically and saving the newly
children automatically is going to take some getting used to.

Now I have a question with my update method. I'll need to delete the
existing children and add in the new children (assume a form similar to
the one for a new parent with one text field for the children).

The following works fine, but I'm wondering, is there more auto-magic I
am not taking advantage of?

def update
  @parent = Parent.find(params[:id])
  @parent.children.each { |child| child.destroy }

  params[:childlist][:names].split(/\s+/).each do |name|
    @parent.children << Child.new({ :name => name })
  end

  if @challenge.update_attributes(params[:challenge])
      redirect_to :action => 'list'
  else
    render :action => 'edit'
  end
end
E34331b0673de4add7fd825a0848cc04?d=identicon&s=25 Evan Haveman (emh)
on 2006-02-25 11:30
sorry, code should have read:

def update
  @parent = Parent.find(params[:id])
  @parent.children.each { |child| child.destroy }

  params[:childlist][:names].split(/\s+/).each do |name|
    @parent.children << Child.new({ :name => name })
  end

  if @parent.update_attributes(params[:parent])
      redirect_to :action => 'list'
  else
    render :action => 'edit'
  end
end
This topic is locked and can not be replied to.