Click here to Skip to main content
15,880,392 members
Articles / Programming Languages / Ruby

Rails 3.2: A Nested-Form Demo, Part 2: Accelerate to Attack Speed!

Rate me:
Please Sign up or sign in to vote.
4.00/5 (1 vote)
28 Jan 2013CPOL5 min read 10.6K   2  
Rails 3.2: A Nested-Form Demo, Part 2


In our previous post, our intrepid heroes were hurtling headlong into the trenches of the Starfighter Recognition Guide. They maneuvered through the superstructure of the application, setting up a relationship between themselves (the Pilots) and the Ships they fly. In this post, our ace Rebel pilots will make their approach to the surface of our application.

The Controller

Because all of the heavy lifting is being handled by the ActiveRecord configuration defined in our domain model, the controller for the Ship model is pretty standard fare. As a quick refresher, here's what the create method in the ships_controller looks like:

def create
  @ship =[:ship])

    redirect_to(ships_path, :notice => "The #{ } ship has been saved successfully.")
    render(:new, :error => @ship.errors)

If you're interested in looking at the controller in its entirety, you can check it out here.

The Helper Methods

Taking a cue from the Railscast, I've added a couple of helper methods to make my life a little easier:


module ApplicationHelper
  def link_to_remove_fields(name, f, options = {})
    f.hidden_field(:_destroy) + link_to_function(name, "remove_fields(this)", options)

  def link_to_add_fields(name, f, association, options = {})
    new_object = f.object.class.reflect_on_association(association)
    fields = f.fields_for(association, new_object, :child_index => "new_#{ association }") do |builder|
      render(association.to_s.singularize + "_fields", :f => builder)

    link_to_function(name, "add_fields(this, \"#{ association }\", \"#{ escape_javascript(fields) }\")", options)

The code above is lifted pretty much verbatim from the Railscast, but I still think it's worth going over:

  • link_to_remove_fields: This method will create a hidden _destroy field (which tells us whether or not the record should be deleted) and a hyperlink that will invoke a javascript method to update our _destroy field.
  • link_to_add_fields:This method will:
    • Create a new instance of our association object (a new Pilot in this case).
    • Builds a form that we can use to edit our new Pilot object.
    • The :child_index will be a placeholder that will be replaced by a unique value generated in javascript (more on that in a minute).
    • Build a hyperlink containing a form for our Pilot object.

The fields_for Method

Let's take a look at what's going on with the second and third lines of link_to_add_fields (lines 8 and 9 in the code shown above). We're using the <a href="" data-mce-href="">fields_for</a> method to build the Pilot input fields for us. At a high level, the fields_for method allows us to build an HTML form without the <form> tags. That means we can put our fields in the "parent" form without any problems.

The fields_for method takes a few parameters:

  • record_name: The name of the type of record we want to create. In our case, we'll pass "Pilots" for this parameter.
  • record_object: An instance of the object we want to add/edit. In our case, this will be a Pilot object. We created a new Pilot object on the previous line of our link_to_add_fields method (line 7 in the code shown above).
  • options: Any options that we might want to pass to the fields_for method. In our case, we want a way to uniquely identify each Pilot we create. So, we use a :child_index, and set it to a "placeholder". For this specific example, our placeholder text will be "new_pilots". This placeholder will be replaced with a unique identifier when the form is shown (i.e. when the add_fields javascript method is called).

In our fields_for block, we're asking it to render our <a href="" data-mce-href="">_pilot_fields.html.erb</a> partial view. Observe the second parameter, :f => builder is the parent form (i.e. the form that contains the input fields for the Ship we're working with). This means that the Pilot fields rendered in our call to fields_for will be a part of the "Add a Ship" form, which is exactly what we want.

At this point, our fields variable should look like a bit like this (tidied up so it can actually be read):


This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Written By
Fairway Technologies
United States United States
Who is the man behind FairwayTech?

My friends call me Jeff.

By day, I'm a mild-mannered programmer for a San Diego software development and consulting company called Fairway Technologies ( By night, I fight crime as a mystery-solving musician.

It all started in a not-so-secret, un-government lab located in San Diego. Fresh out of the Army and recovered from my injuries, I was walking past one of the IT guys who was busily writing an SQL query. I spent a few minutes talking to him about what he was doing, and I was hooked.

Thus began my IT career.

I spent most of my free time studying SQL, pitching in around the office where I could. Before too long, I landed a job in IT as an MS SQL Server DBA (which also involved maintaining some AIX machines, long story) in May of 2000. Somewhere during the 3.5 years of late nights and 70+ hour weeks, I started poking at VB6 and writing the occasional in-house program. I got picked up by the MS Development team (at the same company) to help migrate an app from VB6 to .NET 1.1, and it's pretty much downhill from there. I've spent the vast majority of my IT career working w/the Microsoft technology stack.

Oh yeah - the musician thing. When I'm not merrily coding away, I take the stage with a few bands here in San Diego: Channel (with Mike Mannion and Noah Heldman, also Fairway employees), Christopher Dale and SweetTooth.

Comments and Discussions

-- There are no messages in this forum --