views:

47

answers:

2

I am trying to save many new objects in a form to one pre-existing parent object.

- form_for :parent_object do |f|

This is the beginning of my form. And then within it, I would do:

  - 2.times do
    - fields_for :child_object do |f|

Now if I were to save this, it would render as an ParentObject_Controller Update action which would fail because Update doesn't identify new objects.

So if I wanted to render the appropriate Save action, I would have to set up like this :

- form_for [@parent_object, @child_object] do |f|
  - 2.times do
    - fields_for :child_object do |f|

This form then renders the Save action, but only saves the last child_object.

I would show you my controller, but there's hardly a point because its devastatingly erroneous.

My question is, how would you save many new objects in a form to one pre-existing parent object?

I have looked extensively at Ryan Bate's work, and many many other blogs and SO posts regarding this. Nothing seems to really point at specifically creating new child objects for one pre-existing parent object.

Update:

I am under the impression that I have to toggle the parent_object's controller actions for def update.

  elsif params[:parent_object][:child_object]
    @child_object = Child_Object.new(params[:child_object])
    if @child_object.valid? && @parent_object.referrals << @child_object
      redirect_to new_parent_object_child_object_path(@parent_object)
    else
      render :action => :new
    end

In debugger, if I I place a debugger at the root of def update, and I write :

>> params[:parent_object]
#=> nil

Interesting! That means that when child_object is send to parent_object controller, the params are not filled out for it. Haha, no idea what to do about it though..

Unfortunately that code doesn't work, it was just my attempt at getting closer. ;)

A: 

You can take a look at this answer I gave to a similar question. There're two options: with separate forms, or with a single form.

You'll just have to change the moderate_names_path to the correct path to your parent model instance (and of course the set of fields you want to modify). You can do it with polymorphic_path:

polymorphic_path([@parent_object, @child_object])
Matt
@Matt, I have an explicit url set for this already. `- form_for [@parent_object, @child_object :url => parent_object_child_object_path do |f|` Why make a polymorphic path? You're saying that allows the ability to save multiple objects in one form?
Trip
@Matt, Hmm.. If I were to create a custom def for parent_object, what would that include? Thanks for your help, I've been stuck on this for days. :D
Trip
Well, maybe these examples aren't exactly what you need. Which RB screencasts have you tried? This one: [Nested Model Form](http://railscasts.com/episodes/196-nested-model-form-part-1)? It seems to describe exactly what you want.
Matt
I have watched that 10x over including the Complex Forms 1-3. The nested model form doesn't work because it references **pre-existing** child_objects where as mine are **new** objects.
Trip
See my other answer - when editing, the nested model doesn't reference pre-existing objects. It builds some empty objects on request, in the `edit` method of the controller, but doesn't save them, so they're only available in the form.
Matt
+1  A: 

OK, let's give it another shot. Code taken from RB's screencast with replaced object names:

<% form_for @parent_object do |f| %>  
  <%= f.error_messages %>  
  <!-- some field of parent object here -->
  <p>  
    <%= f.label :name %><br />  
    <%= f.text_field :name %>  
  </p>  
  <% f.fields_for :child_objects do |builder| %>  
  <!-- some fields for child objects -->
  <p>  
    <%= builder.label :content, "Some content for child object" %><br />  
    <%= builder.text_area :content, :rows => 3 %>  
    <%= builder.check_box :_destroy %>  
    <%= builder.label :_destroy, "Remove child object" %>  
  </p>  
  <% end %>  
  <p><%= f.submit "Submit" %></p>  
<% end %>

This is a form for @parent_object that has fields for :child_objects. Of course, you've to replace fields with your own.

To make this work, you'll have to build child objects in the constructor:

def new  
  @parent_object = ParentObject.new  
  3.times { @parent_object.child_objects.build }  
end 

Similarly in the edit method, you'd do:

def edit  
  @parent_object = ParentObject.find(params[:id])
  3.times { @parent_object.child_objects.build }  
end

To make it work, you need to define the nested attributes for child object:

class ParentObject < ActiveRecord::Base  
  has_many :child_objects, :dependent => :destroy  
  accepts_nested_attributes_for :child_objects
end    

Hope this helps - this is exactly what RB proposes in his screencasts. Let me know in the comments if you need some further explanation.

-- EDIT --

The update method in the parent_object_controller.rb is just a standard one:

def update
  @parent_object = ParentObject.find(params[:id])
  if @parent_object.update_attributes(params[:parent_object])
    flash[:notice] = "Successfully updated parent object."
    redirect_to @parent_object
  else
    render :action => 'edit'
  end
end

But thanks to the accepts_nested_attributes_for in the ParentObject, the nested instances will be created as well.

I didn't include all the model and controller code in this response. You can see the rest of the code by downloading source code for this episode from github.

Matt
@Matt, wow I can't thank you enough. Really, this particular screencast is probably the closest, I agree. so..the big dilemma i run into here is that when i click submit, or save, the action rendered, is looking for a parent_object's Update action.. ah.. getting closer here. i suppose i just have to update something with the parent's controller ?
Trip
The Log : `Processing Parent_ObjectsController#update (for ::1 at 2010-10-19 12:10:43) [PUT] Parameters: {"commit"=>"Submit", "Child_Objects"=>{"name"=>"jhkhjk", "org_name"=>"jhkjhk", "town"=>"kjhkjh", "email"=>"jhkjh"}, "action"=>"update", "_method"=>"put", "authenticity_token"=>"F2ZA2/BilvDrcOv+4XZ8Md63mbZBce/y9hIjJJZ42pw=", "id"=>"1", "controller"=>"Parent_Objects"}`
Trip
See update to my answer below for the `update` method.
Matt
Ah thanks for the follow-up. Yes I have that. Trouble is it doesn't recognize `params[:parent_object]` for whatever reason. Mighty strange because I have quite a few child_objects working the exact same way, and none of them have the trouble of recognizing the parent_object.
Trip
Your log shows there's no data for parent_object sent, only child_objects. Not sure why that is. Compare carefully your form with the view code (form_for) I gave as an example. Try to download and run RB's example and compare your code and log outputs with it.
Matt