I have a "dialog" type page for the user to update a set of conditions
on an object. These Condition objects are associated with the parent
obj thru an association. The page lets them remove existing
associations or make new ones.
I want to present Update and Cancel buttons for the user. If the user
hits Cancel, I want to discard all of the changes and go back to the
original state.
There are several approaches I can think of, but I wanted to hear what
others think the best way might be. (BTW - I'm still on Rails 1.2.5,
in case there's something groovy in this regard in 2.0... I'm not
ready to upgrade yet)... Here's what I've thought of and what to do in
case of Cancel:
1) use transactions and rollback - might be the cleanest, but I havent
used them yet in rails and I dont know if there are gotchas I'll need
to learn about
2) clone or dup the parent object and discard - from my quick reading,
I'm not sure the shallow copying copies the associations... and if it
does, whether it creates new associated objs or not... and then what
it does when I discard
3) track the changes and unwind - pretty messy
As always, any help from the group is much appreciated.
Transactions definitely won't work. First, you'd have to stretch the
transaction across HTTP requests, because you'd start the transaction
in one action, and then either roll it back in the Cancel action or
commit it in the Update action. You never want to allow user
interaction inside a transaction because the user might drop dead.
Second, I don't even know if you _can_ stretch a trx across requests
in Rails.
You might consider looking at the Memento design pattern (I don't know
if it's in the Ruby patterns book).
I realize that I left out some missing details to my original post...
1) the user clicks an Update Conditions button to go to the page
2) The user updates the associated list of Conditions by adding new
ones or removing existing ones thru a 2 AJAX interactions. Existing
Conditions are listed with a UI element that they can click to remove.
New Conditions can be added from a menu. So, the user can execute a
series of Add or Remove actions while still on the page.
3) the idea was to let them commit the entire set of actions by
clicking an Update button or discard the set by clicking a Cancel
button
One problem with all of this is that the user can, of course, just
click away from the page without using either the Update or Cancel
button. So perhaps this UI isnt the best.
But, I'm still curious how people have approached being able to
reverse/undo/cancel a set of actions like I've described.
I chose to rewrite part of my code so that the addition/removal of
these associated objects is not actually done on the model itself
until the user commits the changes by clicking the Update button.
Instead, I load up a session variable with an array of refs to the
associated objs, manipulate that list (add/removes) while still on the
page, then apply the final set to the model. Pretty clean and easy.