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:
- At the command prompt, create a new Rails application:
rails new myapp
(wheremyapp
is the application name). If you want HTML5 goodness thenrails new myapp -m https://github.com/russfrisch/h5bp-rails/raw/master/h5bp.rb
. cd myapp
rails g scaffold Mom name:string
rails g model Kid name:string mom:references
- Add the following lines to
app/models/mom.rb
has_many :kids, :dependent => :destroy accepts_nested_attributes_for :kids, :allow_destroy => :true
rake db:migrate
- In
config/routes.rb
, changeresources :moms
toresources :moms do resources :kids end
rails g controller Kids
- 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
- 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' %>
- Create a file
app/views/kids/_kid.html.erb
with the following code:<p> <strong>Kid:</strong> <%= kid.name %> <%= link_to 'Remove', [kid.mom, kid], :confirm => 'Really remove kid?', :method => :delete %> </p>
- Create a file
app/views/kids/_form.html.erb
with 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 %>
rails s
- Point your browser to
https://localhost:3000/moms
.