Adding multiple invoice items to an invoice on the same form

Hi Friends ,
Got a unique requirement .I am designing a invoice printing system
.So right now I have the NEW page for adding the invoice details to the
table .Now I have the requirement of adding Invoice Items In the same
form .I have added multiple text boxes to enter the values of the Items
using
<%= text_field ‘invoiceitems[]’, ‘item_price’ %>
<%= text_field ‘invoiceitems[]’, ‘item_qty’ %> etc.

How can I save the multiple items in the same form .I have to insert the
invoice details and the invoice items on the same button click.

Waiting for the comments and suggestions ,

Thanx and regards,
Naroor R.,
www.naroor.blogspot.com

Not an expert but I will take a shot here. The form looks right to me
however I did things a little different. I used different names for
each field type (so that I had different arrays returned to the
server) and than did a loop through the array by something like this:

0.upto.(params[invoiceprice].length - 1) do |x|
invoice << Invoice.new(:invoiceprice => params[:invoiceprice][x],
:invoiceqty => params[invoiceqty][x])
end

I am doing something slimilar however I used text_field_tag and
various other _tag helpers in my view because my form was dynamically
created and I felt that I could not use the non tag fields due to the
fact that I have no preexisting knowledge of what the form is going
to look like.

Hope this helps, if I did something wrong here would love to be
corrected as well but it seems to work may not be the most DRY way to
do it.

Andrew

On 12/15/05, naroor rathish [email protected] wrote:

invoice details and the invoice items on the same button click.

One way would be to move the text fields you want generated to a
partial.
Let’s pretend it’s called _invoiceitem.rhtml
Then, in your RHTML file, where you currently have those text_field
statements…

Assuming @invoice_items is an Enumerable containing the AR objects

you want to work with.
<%= render(:partial => ‘invoiceitem’, :collection => @invoice_items) %>

_invoiceitem.rhtml would look something like: (First line is
important, if you want to use the form helpers.)
<% @invoiceitem = invoiceitem -%>
<%= text_field ‘invoiceitem’, ‘item_price’, ‘index’ =>
invoiceitem_counter %>
<%= text_field ‘invoiceitem’, ‘item_qty’, ‘index’ => invoiceitem_counter
%>

And so on, for the various attributes you want to display.

nameofpartial_counter is a local variable created for you that keeps

track of the index.

In the controller action that your form submits to, you’d do something
like:

@items = []
params[:invoiceitem].each do |key, item|
@items << InvoiceItem.new(item)
end

Now you’ve got an array of all the invoice item objects, and you can
do whatever you want with it… maybe stuffing it in the session for
later use, or calling “.valid?” on each entry and putting something in
the flash if any of them aren’t correct, etc.

Hopefully someone will come along and show a more elegant solution
that I just don’t know about yet, but this is roughly how I do it.

–Wilson.

I’ve been doing roughly the same thing, using the :index in each form
field to pass an index for each line item.

Since the same partial is going to get used for both new invoices and
editing existing invoices, what you may want to do is name the variable
that contains the :index value more generically so that when calling
“new.rhtml” you pass :index that invoice_item counter’s value (3 rows?
then pass it 1, 2, and 3 in a loop), and when you’re calling the partial
from “edit.rhtml” you’re passing it invoice_item.id.

You’ll have to go through a bit more contortion if you want to mix new
lineitems with edits of old ones on the same edit form, obviously, since
you’ll need a way for your update action to distinguish between the
different purposes you’re using :index for.


-sk

Wilson B. wrote:

On 12/15/05, naroor rathish [email protected] wrote:

invoice details and the invoice items on the same button click.

One way would be to move the text fields you want generated to a
partial.
Let’s pretend it’s called _invoiceitem.rhtml
Then, in your RHTML file, where you currently have those text_field
statements…

Assuming @invoice_items is an Enumerable containing the AR objects

you want to work with.
<%= render(:partial => ‘invoiceitem’, :collection => @invoice_items) %>

_invoiceitem.rhtml would look something like: (First line is
important, if you want to use the form helpers.)
<% @invoiceitem = invoiceitem -%>
<%= text_field ‘invoiceitem’, ‘item_price’, ‘index’ =>
invoiceitem_counter %>
<%= text_field ‘invoiceitem’, ‘item_qty’, ‘index’ => invoiceitem_counter
%>

And so on, for the various attributes you want to display.

nameofpartial_counter is a local variable created for you that keeps

track of the index.

In the controller action that your form submits to, you’d do something
like:

@items = []
params[:invoiceitem].each do |key, item|
@items << InvoiceItem.new(item)
end

Now you’ve got an array of all the invoice item objects, and you can
do whatever you want with it… maybe stuffing it in the session for
later use, or calling “.valid?” on each entry and putting something in
the flash if any of them aren’t correct, etc.

Hopefully someone will come along and show a more elegant solution
that I just don’t know about yet, but this is roughly how I do it.

–Wilson.

When you render a partial by passing in a collection, the render()
call automatically provides a counter object for you.
It gives this object the name #{partialname}_counter… In this case,
invoiceitem_counter.
The first line (@invoiceitem = invoiceitem) is necessary because there
is no way in Ruby to ask a variable what its name is.
To work around this, the Rails helpers (such as text_field) take the
name of the object as a string (‘invoiceitem’), and then use that when
they need to access the object.
The helpers, however, are coded to expect an instance variable.
text_field(‘blah’, ‘blah_property’) requires that there be an instance
variable @blah.

When working with a collection, the objects are passed in as locals
(invoiceitem), so we need to turn them into instance variables
(@invoiceitem) before using helpers on them.

The problem with your code, at first glance, seems to be that you’re
not actually working with a collection. Your first partial call only
has one item, and subsequent invoice items are added one at a time,
via Ajax. This means that you need to keep track of the ‘item count’
separately, probably via an instance variable in the controller.
The Ajax action will need to increment that number by one when it
fires, and you’ll use that number as the index of the next item to be
added.

Good luck,
–Wilson.

Hi Wilson ,
I was trying your code to be implemented in mine but some errors are
coming .
I added a partial ::
<% @invoiceitem = invoiceitem -%>
<%= text_field ‘invoiceitem’, ‘item_price’, ‘index’ =>
invoiceitem_counter %>
<%= text_field ‘invoiceitem’, ‘item_qty’, ‘index’ =>
invoiceitem_counter
%>
Where are we initialising the counter? Please tell how is the first line
working .

In the rhtml file I have added :

<%= form_remote_tag(:update => "my_list",
                   :url => { :action => :add_new_item },
                   :position => "bottom" ) %>

        <%= submit_tag "Add New Item" %>
   <%= end_form_tag %>
  • Original item... please add more!
<%= submit_tag 'Update' %>
I have added like this for creating a dynamic generation of text boxes using ajax.

And in the controller class ,

def add_new_item

render(:partial => ‘invoiceitems’, :collection => @invoice_items)

end
def save_items

 @items = []
params[:invoiceitem].each do |key, item|
	@items = InvoiceItem.new(item)
end

end

Please help my in implementing this requirement .

Thanks and regards,
Naroor R…

Wilson B. wrote:

On 12/15/05, naroor rathish [email protected] wrote:

invoice details and the invoice items on the same button click.

One way would be to move the text fields you want generated to a
partial.
Let’s pretend it’s called _invoiceitem.rhtml
Then, in your RHTML file, where you currently have those text_field
statements…

Assuming @invoice_items is an Enumerable containing the AR objects

you want to work with.
<%= render(:partial => ‘invoiceitem’, :collection => @invoice_items) %>

_invoiceitem.rhtml would look something like: (First line is
important, if you want to use the form helpers.)
<% @invoiceitem = invoiceitem -%>
<%= text_field ‘invoiceitem’, ‘item_price’, ‘index’ =>
invoiceitem_counter %>
<%= text_field ‘invoiceitem’, ‘item_qty’, ‘index’ => invoiceitem_counter
%>

And so on, for the various attributes you want to display.

nameofpartial_counter is a local variable created for you that keeps

track of the index.

In the controller action that your form submits to, you’d do something
like:

@items = []
params[:invoiceitem].each do |key, item|
@items << InvoiceItem.new(item)
end

Now you’ve got an array of all the invoice item objects, and you can
do whatever you want with it… maybe stuffing it in the session for
later use, or calling “.valid?” on each entry and putting something in
the flash if any of them aren’t correct, etc.

Hopefully someone will come along and show a more elegant solution
that I just don’t know about yet, but this is roughly how I do it.

–Wilson.

If your partial is named _invoiceitems.rhtml, the object will be
‘invoiceitems’, not ‘invoiceitem’.
Take the ‘s’ off the end of the filename, and you should be good.

Hi wilson,
Got a strange error.

NameError in Ajax#add_new_item
Showing app/views/ajax/_invoiceitems.rhtml where line #2 raised:

undefined local variable or method `invoiceitem’ for
#<#Class:0x3873970:0x3873898>

Extracted source (around line #2):

1:
2: <% @invoiceitem = invoiceitem %>
3: <%= text_field ‘invoiceitem’, ‘item_price’, ‘index’ =>
invoiceitem_counter %>
4: <%= text_field ‘invoiceitem’, ‘item_qty’, ‘index’ =>
invoiceitem_counter %>

Request
Parameters: {“commit”=>“Add”, “_”=>""}

Show session dump


flash: !ruby/hash:ActionController::Flash::FlashHash {}
Response
Headers: {“cookie”=>[], “Cache-Control”=>“no-cache”}

Can’t we use ajx with partials .Please let me know the result.

Thanking you,
Naroor R.

Hi Wilson,
Thanx for the comments .That got cleared but final saving issues .
The error is
NameError in Ajax#save_items
uninitialized constant Invoiceitem
RAILS_ROOT: ./script/…/config/…

Request
Parameters: {“commit”=>“Update”, “invoice”=>{“inv_number”=>“rest”},
“invoiceitem”=>{“1”=>{“item_price”=>“12”, “item_qty”=>“12”},
“2”=>{“item_price”=>“13”, “item_qty”=>“13”}}}

The code I have written for saving is (i mean in the controller is )

def save_items

@invoice = Invoice.new(params[:invoice])
params[:invoiceitem].each do |key, val|
        @invoice.invoiceitems << Invoiceitem.new(val)
end

end

Calling the partial is like
render(:partial => ‘invoiceitems’, :collection => @invoiceitems )

In the partial I have given,
<% $count = $count + 1 %>
<% @invoiceitem = invoiceitems %>
<%= text_field ‘invoiceitem’, ‘item_price’, ‘index’ => $count %>
<%= text_field ‘invoiceitem’, ‘item_qty’, ‘index’ => $count %>

Please help me out.
Thanx and regards,
Naroor R.

Hi Wilson ,
The same error
NoMethodError in Ajax#save_items
undefined method `invoice_items’ for #Invoice:0x385a920
with
Request
Parameters: {“commit”=>“Update”, “invoice”=>{“inv_number”=>“inv123”},
“invoiceitem”=>{“1”=>{“item_price”=>“12”, “item_qty”=>“12”},
“2”=>{“item_price”=>“13”, “item_qty”=>“13”}}}

Should the name of the table be invoice_items ??Right now I have the
name of the table as invoiceitems .

Thanx,
Naroor R.

@invoice.invoiceitems << Invoiceitem.new(val)

…should instead be:
@invoice.invoice_items << InvoiceItem.new(val)

Hi Wilson ,
The results I am getting in each variables are

params[:invoice] = inv_number123

params[:invoiceitem] =
1item_priceprice1item_qtyqty12item_priceprice2item_qtyqty23item_priceprice3item_qtyqty3

Is the output correct when I dynamically added 3 rows with two columns
for entering intem price and quantity .

Regards,
Naroor R.

On 12/22/05, Naroor R. [email protected] wrote:

Should the name of the table be invoice_items ??Right now I have the
name of the table as invoiceitems .

Yeah, the table needs to be called invoice_items, or else you need to
override the table with set_table_name in your model class.
params[:invoiceitem] contains a Hash that has index numbers from the
view as its keys, and hashes as values. Those hashes it contains use
field names as their keys.
e.g.
items = params[:invoiceitem]
second_item = items[:2]
second_item is now a Hash with two keys… :item_price and :item_qty

second_item[:item_price] == ‘13’

–Wilson.