Topic: Multiple rows of data with a single form

I've been trying to configure a submit form where users can add multiple names to a database at once, instead of individually.

So far, here's the code I have for my view:

<% form_for(:owner, :url => owner_path) do |f| %>
    <% (1..3).each do |i| -%>
    First Name: <%= f.text_field :firstname, :index => i  %>
    Last Name: <%= f.text_field :lastname, :index => i  %>
    <% end -%>
   
    <%= submit_tag "Add Names" %>
<% end %>

While this properly generates the form, I seem to be having a problem with the controller. Originally, here's what I had in my controller:

def create
  @owner = Owner.new(params[:owner])
  if @owner.save
    flash[:notice] = 'Owner was succesfully added.'
    redirect_to :action => 'unpaid'
  else
    render :action => 'new'
  end
end

This resulted in an error saying "undefined method `1=' for #<Owner:0x260f4cc>". I played around a bit and changed the first line of the action to this:

params[:owner].each_value { |i| @owner = Owner.new(i) }

However, this just submits a single row of data and ignores the rest.

Any advice would be greatly appreciated. Thanks.

Re: Multiple rows of data with a single form

See my tutorial on creating many models in one form. If you still have questions after that, please post them here.

Railscasts - Free Ruby on Rails Screencasts

Re: Multiple rows of data with a single form

I had read through that tutorial, but I couldn't seem to adopt the code for my project since I'm just interacting with a single model.

Re: Multiple rows of data with a single form

You're right, there are some significant differences. Try this code.

def new
  @owners = Array.new(3) { Owner.new } # set up any defaults here
end

def create
  @owners = params[:owners].values.collect { |owner| Owner.new(owner) }
  if @owners.all?(&:valid?)
    @owners.each(&:save!)
    redirect_to :action => 'index'
  else
    render :action => 'new'
  end
end

# in new.rhtml
<%= start_form_tag :action => 'create' %>
<% @owners.each_with_index do |owner, index| %>
  <% fields_for "owners[#{index}]", owner do |f| %>
    First Name: <%= f.text_field :firstname  %>
    Last Name: <%= f.text_field :lastname  %>
  <% end %>
<% end %>
<%= end_form_tag %>


If you have any questions about the code feel free to ask.

Railscasts - Free Ruby on Rails Screencasts

Re: Multiple rows of data with a single form

Can someone please show me what the 'edit' / 'update' actions would look like? I am kind of stuck. Much obliged

Re: Multiple rows of data with a single form

Have you read the tutorial editing multiple models in one form?

Railscasts - Free Ruby on Rails Screencasts

Re: Multiple rows of data with a single form

My code works in internet explorer 7.00 but not in Safari or Firefox when adding more than one item can anyone tell me why
Thanks
Martin

 
Models
BakeryOutput
belongs_to  :recipe

Recipe
has_many  :bakery_outputs

Controller
  def new
    @bakery_outputs = Array.new(1) {BakeryOutput.new}
  end
 
  def create
   # @bakery_output = BakeryOutput.new(params[:bakery_output])
    @bakery_outputs = params[:bakery_outputs].values.collect { |bakery_output| BakeryOutput.new(bakery_output)}
    if @bakery_outputs.all?(&:valid?)
      @bakery_outputs.each(&:save!)
      redirect_to :action => 'index'
    else
      redirect_to :action => 'new'
   end

  def add_product
    @bakery_outputs = BakeryOutput.new
  end

Views
new.rhtml
<div id="sales_content" align="center">
<h3>Sales<%= error_messages_for :bakery_output %>
      <% form_for(:bakery_output, :url => bakery_outputs_path) do |j| %>
    </h3>
<div id="headings">
<b>Customer</b>
    <b>Product</b>
    <b>Qty</b>
   <b>Date</b>
    <b>Batchcode</b>
</div>
<div id="products">
    <% @bakery_outputs.each_with_index do |bakery_output, index| %>
        <%= render :partial => 'product_fields', :locals => {:bakery_output => bakery_output, :index => index }%>
    <% end %>
</div>

    <%= render :partial => 'add_product_link', :locals => { :index => @bakery_outputs.size}%>
<%= submit_tag "Save All" %>
  <% end %>
    <%= link_to 'Cancel', bakery_outputs_path %>
</div>

Partials
<div id="add_product_link">
    <%= link_to_remote 'Add another sale', :url =>  {:action => 'add_product', :index => index} %>
</div>

<div id="product_<%= index %>">
    <% fields_for "bakery_outputs[#{index}]", bakery_output do |f| %>

<% @customers = Customer.find(:all, :select => "id, company", :order => "company")%>
  <%= f.select(:customer_id, @customers.map{|u| [u.company, u.id]} + ['Add New']) %>
<% @recipes = Recipe.find(:all, :select => "id, name", :order => "name")%>
  <%= f.collection_select(:recipe_id, @recipes, :id, :name) %>
<%=  f.text_field :sales_quantity, :size =>3 %>
<%= f.date_select :saledate, :order => [:day, :month, :year]%>
<%= f.text_field :salebatchcode, :size => 10 %>

    <% end %>
    </div>

Re: Multiple rows of data with a single form

I have this same situation and can't for the life of me get it figured out. I have read all three "multiple model, multiple record" tutorials, followed the chapter from Advanced Rails Recipes, and tried posting on another section of this site, but to no avail.

The example from the Advanced Rails Recipes book looks like almost exactly what I need, but I can't get it to work for my single-model situation. I can get the form to submit and pass the right params, but I'm certain there is something not right in my controller or model code, but I have no clue where.

Re: Multiple rows of data with a single form

Thanks to Mr. Ryan,

For providing such an important code. I had to modify it a bit to make it compatible with Rails 2. I have been struggling a lot to find the solution to the problem reported in this thread.

Here is the modified code compatible with Rails 2.

### Your controller
def new
   @owners = Array.new(3) { Owner.new } # set up any defaults here
end

def create
   @owners = params[:owners].values.collect { |owner| Owner.new(owner) }
   if @owners.all?(&:valid?)
     @owners.each(&:save!)
     redirect_to :action => 'index'
   else
     render :action => 'new'
   end
end

### Your View - new.erb.html
<% form_tag :action => 'create' do %>
<% @owners.each_with_index do |owner, index| %>
   <% fields_for "owners[#{index}]", owner do |f| %>
     First Name: <%= f.text_field :firstname  %>
     Last Name: <%= f.text_field :lastname  %>
   <% end %>
<% end %>
        <%= submit_tag %>
<% end %>

Last edited by ankit644 (2009-03-23 00:03:16)

Re: Multiple rows of data with a single form

Well, the above solution works in its simplicity.
But I couldn't get the error messages to display. How to display validation error messages for individual row of data? And how to discard the invalid model, ie. shown 3 fields and the user just fills in 2?

Re: Multiple rows of data with a single form

hi.... I am a noob to rails  and also new to the forum...kindly excuse me for my mistakes.....anyways for the past few weeks i am stuck at a certain problem of submitting multiple rows at the same time...but i guess i have a unique problem in itself...

my new form looks like this... its actually a partial (_new.rhtml) which renders another form fields partial (_form2.rhtml)

<div class="in_new_div">
  <% form_remote_tag :url => {:action => 'create'}, :update => "body" do %>

    <div id = "new_form" >
       <%= render :partial => 'form2' %>
    </div>

    <%= link_to_function "Add More" do |page| page.insert_html :bottom, :new_form, :partial => 'form2', :object => Expense.new end %>
    <%= submit_tag "Create" %> <%= link_to_function "Cancel", "this.up('.in_new_div').remove()" %>
  <% end %>  
</div>

here when i click the add more link...more form text fields show up one below each other... so after i click add more 3 times i now have this in the view


Category   Add new Category  Item    Quantity    Price
Created at — : remove
Category   Add new Category Item   Quantity   Price
Created at — : remove
Category   Add new Category Item   Quantity   Price
Created at — : remove
Category   Add new Category Item   Quantity   Price
Created at — : remove
Add More  Create Cancel

where create is a submit button for the form..
what i want is when i click create .. it should create 4 rows in the table. 

currently in the controller i have

def create
    @expense = Expense.new(params[:expense])
    @expense.user_id = session[:user_id].to_i    # i have set attr_protected :user_id in the model
    .....
    ....
end

what changes should i made in order to create dynamic number of records (in this case 4) when i click the submit button..
Thanks for the help in advance

Last edited by varun.coolmax (2009-12-14 21:57:00)

Re: Multiple rows of data with a single form

I'm bumping this because I'm having the same exact problem Varun describes in the post above.

We're both using the method described in the the Railscasts series Complex forms, but how do we modify it for just one model, but many times created dynamically by the user?

Re: Multiple rows of data with a single form

ryanb wrote:

Have you read the tutorial editing multiple models in one form?

Hi Ryan -

Your Railscasts are excellent. The multiple models-one form was one I was particularly interested in - do you have any plans to refactor the code so it works under Rails 2? Downloading the code and firing it up (Rails v 2.3.5) fails. Were I not relatively new to Rails, it might be an easy fix. As I am not, it is not.

If not, no worries - I am not complaining at all, just working around the issues in my own slow way.

Thanks for the free Railscasts, and for anyone who has not looked at Ryans in-depth, for-pay screencasts, available at Pragmatic, they are worth every penny.

Re: Multiple rows of data with a single form

I have the same problem that is mentioned above. Is there any way of discarding an unfilled row? I tried adding conditional statements, but with no luck.

Thanks in advance.

Re: Multiple rows of data with a single form

How does this same scenario (multiple rows of data with a single form) workout when the inputs are checkboxes?

Usecase : the form collects the interests of users. There are 3 interest types that are in the database (interesttype table, name:string values are music, lights, editing).

the input form should have a all the 3 interest types displayed as 3 checkboxes and user can select their interests.

the form also has an input text field called 'comments'

if 3 interest types are selected then 3 objects need to be written into the association table one for each interest
if only one interest type is selccted then only 1 object needs to be written into the association table.

---------------------------------
my controller:
-----------------------
def new
     @userinterests = Array.new(10) { Userinterest.new } #userinterest has the interesttype_id and user_id

end

what will the view look like for checkboxes??

any help is apprecaited.

Thanks
Sumi

Re: Multiple rows of data with a single form

I tried this example, but it has problems with "validates_uniqueness_of" test, anyone knows the solution?

Re: Multiple rows of data with a single form

How Will I save The Date Attribute  . i have a date , month and year attribute with the data type string to my model
and whenever i try to save the date year and month i get the

Re: Multiple rows of data with a single form

How Will I save The Date Attribute  . i have a date , month and year attribute with the data type string to my model
and whenever i try to save the date year and month i get the error
"undefined method "day="

here is my controller

def create   
    @ledger   = params[:ledger].values.collect { |ledger| Ledger.new(ledger) }
       @date.day  = params[:date][:day]
       @date.month  = params[:date][:month]
       @date.year = params[:date][:year]
             if @ledger.all?(&:valid?)
                  @ledger.each(&:save!)
                    redirect_to :action => 'index'
          else
               render :action => 'new'
            end
          end

here is the view :


<div id ="form">
<br />
<p><b><%= f.label:"Date" %></b><p>
<p><%= select_day(1, :prompt => 'Choose day',:field_name => 'day')%>
<%= select_month(Date.today, :field_name => 'month') %>
<%= select_year(Date.today,  :field_name => 'year',:start_year => 1985, :end_year => 2050, :field_name => 'year') %></p>

<p><b><%= f.label:"Account Name" %><p>
<p><% @finaccounts = Finaccount.find(:all, :select => "id, account_name", :order => "account_name")%></p>
<p><%= f.select(:finaccount_id, @finaccounts.map{|u| [u.account_name, u.id]} + ['Add New']) %>
<%= link_to_remote "Add Account",:url => {:controller => "finaccounts", :action => "new" }%></p>

<p><b><%= label_tag:"Account Type" %></p>
<p><% @balancesheettypes = Balancesheettype.find(:all, :select => "id, balance", :order => "balance")%></p>
<p><%= f.select(:record, @balancesheettypes.map{|u| [u.balance, u.id]} + ['Add New']) %></p>

<p><b><%= label_tag:Description %></p>
<p><%= f.text_area(:description,  :size => "34x6") %></p>

<p><b><%= label_tag:Debit %></p>
<p><%= f.text_field(:debit,  :size => "5") %></p>

<p><b><%= label_tag:credit %></p>
<p><%= f.text_field(:credit,  :size => "5") %></p>

<p><b><%= label_tag:"Journel" %></th>
<p><% @journels = Journel.find(:all, :select => "id, book_name", :order => "book_name")%></p>
<p><%= f.select(:journel_id, @journels.map{|u| [u.book_name, u.id]} + ['Add New']) %>
<%= link_to_remote "Add Journel",:url => {:controller => "journels", :action => "new" }%></p>
</div>
<br />
<br />


somebody please help
Thank You in Advance

Re: Multiple rows of data with a single form

this is a Damn good tutorial ...but i still have a problem when saving date ..please can somebody tell me how to save multiple dates along with the other attributes.  it gives me an error

Re: Multiple rows of data with a single form

this is a Damn good tutorial ...but i still have a problem when saving date ..please can somebody tell me how to save multiple dates along with the other attributes.

it gives me an error
"undefined method day="

i am trying to save this way !

def new
   @client = Array.new(2) { Client.new }
end

def create
         @client = params[:client].values.collect { |client| Client.new(client) }
         @client.day = params[:date][:day]
         @client.month = params[:date][:month]
         @client.year = params[:date][:year]
                  if @client.all?(&:valid?)
                  @client.each(&:save!)
                    redirect_to :action => 'index'
          else
               render :action => 'new'
            end
          end

i have a three separate variables for date
Day , month , year

<% form_tag :action => 'create' do %>
<% @client.each_with_index do |client, index| %>
   <% fields_for "client[#{index}]", client do |f| %>
          <%= render :partial => 'form', :locals => { :f => f, :clients => @clients } %> 
    <% end %>
<% end %>
     <%= submit_tag %>
<% end %>
<%= link_to "back", clients_path %><br/>

please somebody help ...
just tell me how will i  be able to save the  date  attribute ...please please please ...i am stuck it is been four days ..not clicking any idea ...

thank you in advance

And one more thing I am also new to rails