Topic: Creating children with reference to parent

An extremely dumb question.

I've got a model "parent", and a model "child".

Parent has_many children.

Child belongs_to parent.

All the foreign keys are set up correctly, and I know that it is possible to do the creation because I initially coded the admin system using the sub_list plugin, which created children just fine.  But now I've decided I don't like this style of doing things, because my object structure is deeply nested and the admin form get really unwieldy from a usability point of view.

So, I'd like to take a much simpler approach, and have two forms.  I want to make the form that allows me to create children as its own separate "new" form.

My big dumb question: how do i pass the reference to the parent so that the child can save itself properly?

For the "new" method in the child controller, i've got

def new
  @child = Child.new
  @parent = Parent.find(params[:parent])
end

This part works fine (e.g. @parent.title displays correctly in the page), but when i go to save the child, the @parent goes away, so i get a foreign key violation. Is there some way i need to store the value of @parent in the page so it can get passed back to the child_controller's "create" method?

This is perhaps the dumbest question I have ever asked in a forum, but I am quite honestly stumped as to how to do this.

Re: Creating children with reference to parent

Put the parent ID in as a hidden form field, or a session variable.

Your modeling seems off though since you're talking about people; parents and children aren't mutually exclusive in any way since a parent is also someone's child. Maybe something like acts_as_tree with a generic Person model would work better in your case.

vinnie - rails forum admin

Re: Creating children with reference to parent

Hi Vinnie, thanks for the reply.

I was actually just using the terms "parent" and "child" to illustrate the problem, in actuality my models are named "project" and "concept" which I thought it'd be harder for people to figure out when posting to the forum.

I am surprised that I need to manually construct a hidden form field, I was sort of wondering if Rails had something built-in to handle this (fairly common) case.  But, ok, so it's hidden form field time.

Hm.  I just tried something as a test (I'll stick with the parent/child terminology to try and keep things as clear as I can).

I put this in my _form.rhtml partial:

<p><label for="child_parent_id">Parent id</label>
<p><%= text_field 'child', 'parent_id' %></p>

...and in the child_controller, I put:

  def create
    @concept = Concept.new(params[:concept])
    ...
    @concept.save
    ...
  end

Interestingly, this worked - Rails put @child.parent.id into the form field, and then kept it as a parameter to send back to the "create" method.

Even more interestingly, Rails didn't forget about the rest of the @parent object in this case - not only did it keep the @concept.parent.id, it also kept all the other properties of the parent object, such as @child.parent.title, @child.parent.description, etc.

So, they object must have been stored by Rails somewhere - does anybody understand where?  Or how I can just store @child.parent for resubmission without having to display it? 

I guess what I'm asking is, how does this nifty hidden form field thing actually work?

Re: Creating children with reference to parent

This is now all ironed out, i am just using a

<%= hidden_field 'child', 'parent_id' %>

This results in the form page's HTML source containing:

<input id="concept_project_id" name="concept[project_id]" type="hidden" value="1" />

There are no other properties of @child.parent anywhere in the page, so it must be Active Record doing this stuff for me. 

Aha! Now I understand. Setting a breakpoint before the @child.save and typing @child.parent at the console returns a nil object error...but immediately after the @child.save, @child.parent returns all of its properties - so Active Record is actually saving the child object based on the parent.id in the hidden form field and then refreshing the parent object so it's available to the child object.

Well, this has been educational.  Thanks for the help, Vinnie! Nice forum...