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.

2 Answers 2

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.

Sign up to request clarification or add additional context in comments.

3 Comments

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.
what if you don't know how many records are needed. ex. user can 'add new row' to the form for additional entries.
Take a look here for adding a new row: stackoverflow.com/questions/16919711/…
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 %>

4 Comments

OP should use fields_for with accepts_nested_attributes_for for this.
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?
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?
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

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.