how to make a copy of a collection in the update controller method

I can't figure this out.

Imagine a Ticket object and this object has_many LineItems

Now, my ticket edit form will allow user to modify Ticket attributes and add/modify/delete LineItems at will.

So the edit action sends the LineItems to the form and what comes back could be LineItems in any which way/order or even no LineItems.

With that in mind, I thought, okay, well, I better hold on to the original list of line items somehow in case validation of the Ticket item fails. (no validation of the individual line items, we just throw away the ones that have a blank "item" attribute, but the main ticket attributes do have some validation happening)

In the update controller method I wanted to:

store original line_items in an array or maybe a hash doesn't matter

take the new line items from the form hash and "build" them on to the ticket so, now I have a line_items list that is the original list + what just got added from the form

then, if the Ticket validates, take that original line_items list and delete from ticket's current line_items which again is original list + what got added from the form

the problem is, no matter what I do, I can't seem to save the original_line_items so they don't get touched when processing the line_items from the form

At the very beginning of the update controller method I have:

@ticket = Ticket.find(params[:id]) @line_items = @ticket.line_items

I think my problem is that I don't understand what is happening here. I thought this said:

1) ok, look up the ticket you want to work on, and here's the original line_items for the ticket. 2) now manipulate those via the params from the form ...

I tried stuff like:

orig_line_items = @ticket.line_items

orig_line_items = Array.new(@line_items)

but no luck, no matter what I do, as soon as I start working with @line_items and the params from the form, orig_line_items seems to get changed

I know this because if I start with a ticket with zero LineItems (from script/console I look up the ticket, assign its line items to an array called orig_line_items and then say "is that array empty", answer => true)

but in my controller, even if I added no line_items via the form

@orig_line_items.empty? ----- this is always false, 100% of time, no matter what happened with the form

I'm not understanding a basic form processing concept here I think.

Here's an example of what the form returns, this is good, looks exactly as I expect/want

{"commit"=>"Update Ticket", "ticket"=>{"status"=>"new", "title"=>"tested", "owner"=>"1", "email"=>"test@example.com"}, "id"=>"7", "ticket_extra"=>{"uploaded_data"=>""}, "line_items"=>{"0"=>{"date_created"=>Sat, 06 Dec 2008 20:26:29 +0000, "is_hidden"=>"0", "item"=>"ff"}, "1"=>{"date_created"=>Sat, 06 Dec 2008 20:32:41 GMT +00:00, "is_hidden"=>"0", "item"=>"dd"}}}

@ticket = Ticket.find(params[:id]) @line_items = @ticket.line_items

I think my problem is that I don't understand what is happening here. I thought this said:

1) ok, look up the ticket you want to work on, and here's the original line_items for the ticket. 2) now manipulate those via the params from the form ...

There's two levels of trickery here. First @ticket.line_items isn't an array. At this point the line items have not been loaded. It's a magical association proxy. Even if you were to sidestep that, you're still not copying the array. To put things another way, is

a = [1,2,3] b = a Then b and a are exactly the same array: b << 4 a #=> [1,2,3,4]

I tried stuff like:

orig_line_items = @ticket.line_items

orig_line_items = Array.new(@line_items)

Creating a new Array like that (or duping the original array) should work. I suspect that since you seemed to have been changing stuff slightly in desperation you did something else at the same that clouded the issue.

Fred

Exactly, after more tinkering and such I made it work by copying to an array.

Thanks for taking the time to read my post,