16

I'm new to rails so this is probably a basic question. I am trying to create a form where the user can create 3 records at once. I want the user to only have to click the submit button once. I'm submitting to my Review model a name, comment, and rating. Currently, only the last record is entered into the database.

<%= form_for([@user,@review]) do |f| %>
<table>
  <tr>
    <td>Rank</td>
    <td>Name</td>
    <td>Comment</td>
  </tr>
  <tr>
    <td>1</td>
    <td><%= f.text_field :name %></td>
    <td><%= f.text_field :comment %></td>
    <%= f.hidden_field :rating, :value=> "5" %>
  </tr>
  <tr>
    <td>2</td>
    <td><%= f.text_field :name %></td>
    <td><%= f.text_field :comment %></td>
    <%= f.hidden_field :rating, :value=> "3" %> 
  </tr>
  <tr>
    <td>3</td>
    <td><%= f.text_field :name %></td>
    <td><%= f.text_field :comment %></td>
    <%= f.hidden_field :rating, :value=> "1" %>
  </tr>
</table>
  <div class="actions">
    <%= f.submit "Create my top 3" %>
  </div>
<% end %>

Any advice is appreciated. Thanks.

John
  • 4,362
  • 5
  • 32
  • 50

2 Answers2

26

I would recommend using fields_for for this:

<%= form_for([@user, :reviews]) do |f| %>
  <% @reviews.each do |review| %>
    <%= fields_for review do |r| %>
      <%= render "reviews/form", :r => r %>
    <% end %>
  <% end %>
<% end %>

To make this work, you will need to build as many review objects as you require in your controller:

def new
  # you could also have this in a before_filter...
  @user = User.find(params[:id])
  @reviews = Array.new(3) { @user.reviews.build }
end

This would create new instances of review records for this user, which is different from new records. Instances are simply Ruby objects. Now because you've called @user.reviews.build three times, you'll see three reviews in your view.

def create
  @user = User.find(params[:id])

  @reviews = Review.create(params[:reviews])
  # Some more logic for validating the parameters passed in
end

This will create three new Review objects and link them to @user, assuming all three are valid.

Ryan Bigg
  • 106,965
  • 23
  • 235
  • 261
  • 1
    I'm somewhat confused by your post. The current page that I posted is the reviews#new page, so is the def new in the reviews controller what you are calling "the_action" and likewise whatever_this_is is the def create in the reviews controller? Also where you put 'render/form' what is in render form? Currently, :url => reviews_path) is giving me a name error. Thanks. – John Jan 09 '11 at 23:25
  • 3
    what if you don't know how many records are needed. ex. user can 'add new row' to the form for additional entries. – turbo2oh Feb 06 '13 at 20:03
  • 2
    Take a look here for adding a new row: http://stackoverflow.com/questions/16919711/multiple-non-nested-model-creation-on-same-page/16920211#comment24427696_16920211 – MrYoshiji Jun 04 '13 at 15:58
6

You'll need to tell rails its an array. First, read this section of this article:

For your purpose, you'll need to build the form by hand:

<%= form_tag 'foo' do %>
  <% [1,3,5].each do |i| %>
    <%= text_field_tag 'review[][name]' %>
    <%= text_field_tag 'review[][comment]' %>
    <%= hidden_field_tag 'review[][rating]', :value => i %>
  <% end %>
<% end %>
sethvargo
  • 26,739
  • 10
  • 86
  • 156
  • OP should use fields_for with `accepts_nested_attributes_for` for this. – Ryan Bigg Jan 09 '11 at 21:26
  • 1
    Umm... Does it really matter? This accomplishes the same thing AND this is how the Rails guides do it. Really worth a downvote when it will function correctly? – sethvargo Jan 09 '11 at 21:36
  • I've read the article you linked and a few others, but I'm still having problems getting this too work. The form is rendering correctly, but the 'foo' part is giving me problems. I have replaced foo with user_review_path but it is giving me a routing error? Is there something else I have to do in the new or create controllers or routing file? – John Jan 10 '11 at 22:21
  • You'll need to define a route. Are you nesting :review inside :user. Run the command `rake routes` from within your application's directory and see what names paths you have – sethvargo Jan 11 '11 at 03:01