read

I’m finding Rails quite difficult conceptually. People tell me one day the light will dawn and it will all seem perfectly natural. At the moment though it seems like there’s 1000 ways to achieve any given objective, but only one right one. If you choose one of the other 999 then you’re in a world of manual coding as a result.

I couldn’t find a really basic example of nested forms: a parent record with an arbitrary number of child records. Here’s my attempt to create the simplest possible parent-child forms, with the minimum configuration and the maximum convention. Rails experts: I’d love to reduce this even further - please give me any suggestions for doing so.

The resulting forms can be cloned directly from https://github.com/moo-li/Simple-parent-child-forms-in-Rails-3.1, but here’s how to create them yourself:

  1. At the command prompt, create a new Rails application: rails new myapp (where myapp is the application name). If you want HTML5 goodness then rails new myapp -m https://github.com/russfrisch/h5bp-rails/raw/master/h5bp.rb.
  2. cd myapp
  3. rails g scaffold Mom name:string
  4. rails g model Kid name:string mom:references
  5. Add the following lines to app/models/mom.rb
    has_many :kids, :dependent => :destroy
    accepts_nested_attributes_for :kids, :allow_destroy => :true
  6. rake db:migrate
  7. In config/routes.rb, change resources :momsto
    resources :moms do
      resources :kids
    end
  8. rails g controller Kids
  9. Add the following methods to app/controllers/kids_controller.rb
    def create
      @mom = Mom.find(params[:mom_id])
      @kid = @mom.kids.create(params[:kid])
      redirect_to mom_path(@mom)
    end
    
    def destroy
      @mom = Mom.find(params[:mom_id])
      @kid = @mom.kids.find(params[:id])
      @kid.destroy
      redirect_to mom_path(@mom)
    end
  10. Add the following lines to app/views/moms/show.html.erb before the line containing <%= link_to 'Edit', edit_mom_path(@mom) %> |
    <h2>Kids</h2>
    <%= render @mom.kids %>
    
    <h3>Add kid</h3>
    <%= render 'kids/form' %>
  11. Create a file app/views/kids/_kid.html.erbwith the following code:
    <p>
      <strong>Kid:</strong>
      <%= kid.name %>
      <%= link_to 'Remove', [kid.mom, kid], :confirm => 'Really remove kid?', :method => :delete %>
    </p>
  12. Create a file app/views/kids/_form.html.erbwith the following code:
    <%= form_for([@mom, @mom.kids.build]) do |f| %>
      <div class="field">
        <%= f.label :name %> <%= f.text_field :name %>
      </div>
    
      <div class="actions">
        <%= f.submit %>
      </div>
    <% end %>
  13. rails s
  14. Point your browser to https://localhost:3000/moms.