Carl Youngblood wrote:
> 
>> We use this in seaside (and borges does the same) to allow the user to
>> use the back button in the browser.  No matter how many times the user
>> goes back and clicks a link on the same page, the handling will always
>> be done by the exact same execution context.  It doesn't know it's being
>> called over and over; it just knows it's supposed to handle the clicks
>> generated from that page and it always does.
> 
> 
> Is that always good?  What if it means the users ends up clicking on the 
> purchase button twice and we charge their card twice?  I've always 
> thought that it was best not to let the user use the back button in 
> cases like these (i.e., forward them to the right page, display an error 
> indicating that the posted values are stale, or something like that).

No, it's not always good.  But it's always good to be able to.  Seaside 
(and I believe Borges for Ruby implements this piece too) has a concept 
of transactions or isolate blocks.  The way this works is that you 
execute a section of code inside a block.  When that block terminates, 
all the pages in that session get expired.  So in the case of a shopping 
cart, you would likely start an isolate block when they begin the 
payment process and expire all those pages as soon as they press "Purchase".

Note that you also have control over which pieces of state get 
backtracked with the back button.  So you can have the UI state 
representing, for example, which tab is selected roll back with the back 
button, but leave your model data (such as the shopping cart contents, 
perhaps) so it always represents the newest data.  It requires some 
thought in each case to determine what the desired semantics are, but 
once you decide what you want it's easy to implement either way.

Julian