You are viewing a plain text version of this content. The canonical link for it is here.
Posted to users@cocoon.apache.org by Tobia <to...@linux.it> on 2007/06/04 12:32:47 UTC

Redirect at the end of a form

Cocoon users,

I would like to get your feedback on a piece of flowscript I just wrote
to solve what I believe to be a common problem.

Suppose you have a form that asks the user for some data, validates it
and inserts it into a database, using a DB access layer for flowscript,
such as jdbi.js from the samples.  The basic flowscript would be:

	// create and show the form
	var form = new Form(...)
	form.showForm(...)

	/* execute DB operations to store the newly inserted data */

	//send a results page back to the user
	cocoon.sendPage(...)

The final sendPage() sends a custom page to show the user what he has
just inserted.  Suppose also that said data does not have a public url,
but is only available to the submitting user at the end of the form.

What is the problem with the previous flowscript?  If the user reloads
the final page, the DB operations are executed again, possibly resulting
in duplicate insertions or other errors.

The usual solution to this problem is to issue a client-side redirect to
a GET url, so that subsequent client reloads don't have side effects.

Continuations seem the perfect tool to issue such a redirect to a
private url built on-the-fly for just one user, but I couldn't find an
idiomatic way of doing it in the samples, so I wrote my own.

The following function is called after the DB operations, just before
the final sendPage()

	function redirectToGet() {
	  var done = false
	  var cont = cocoon.createWebContinuation()
	  if (! done) {
	    done = true
	    var url = /* build a url that will call cont.id */
	    cocoon.redirectTo(url, true)
	  }
	}

What do you think?  Is there a better way of doing it?  How is this
problem usually solved?  Any feedback is welcome.


Tobia

---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@cocoon.apache.org
For additional commands, e-mail: users-help@cocoon.apache.org


Re: Redirect at the end of a form

Posted by Baptiste Placé <bo...@free.fr>.
Your solution looks quite concise.
If you use flowscript for all DB transaction, couldn't you have the 
final page make the commit ?
Maybe you can invalidate the continuation created before, not sure how 
to do that.
Hope this help.

-Baptiste

Tobia a écrit :
> In my example I only had one form, so the client/server interaction was
> like this sequence diagram (you will need a fixed font to see it):
>
>
> Client                                 Server (flowscript)
>
> open the page w/ the form    --GET-->  function call
> :                                       \_ new Form()
> :                                       \_ showForm()
> :                                           \_ internal validation loop
> display the form             <·······           \_ sendPageAndWait()
>
> try and submit the form      --POST->           \_ validation FAILS
> redisplay the form           <·······           \_ sendPageAndWait()
>
> try and submit the form (*)  --POST->           \_ validation SUCCEEDS
> :                                       \_ DB operations
> display the results          <·······   \_ final sendPage()
>
>
> Read it like this:
>   1 ---> 2
>          3
>   5 <··· 4
>
> The problem is, if the user doesn't get the final results page (for
> whatever reason) she will hit refresh and the flowscript will resume
> from (*), which is a Bad Thing.
>
> With my addition, the last part of the sequence diagram looks like this:
>
>
> try and submit the form      --POST->           \_ validation SUCCEEDS
> :                                       \_ DB operations
> :                                       \_ redirectToGet()
> :                                           \_ createWebContinuation()
> receive the redirect         <·······       \_ redirectTo()
>
> follow the redirect (*)      --GET-->       \_ return
> display the results          <·······   \_ final sendPage()
>
>
> Any refresh will make the flowscript resume from (*), which is correct.
>
>
> It seems to me that any non-trivial use of createWebContinuation() needs
> a flag variable (var done in my example) and a subsequent test.  Is that
> correct?  Am I missing something?
>
>
> Tobia
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: users-unsubscribe@cocoon.apache.org
> For additional commands, e-mail: users-help@cocoon.apache.org
>   

---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@cocoon.apache.org
For additional commands, e-mail: users-help@cocoon.apache.org


Re: Redirect at the end of a form

Posted by Tobia <to...@linux.it>.
Baptiste Placé wrote:
> Have you tried stocking form data into a collection, and send it to
> the final page?

I'm not sure I understand


> Refreshing the page re-executing the db actions mean the final page
> triggers the DB part of your flowscript.  Maybe your final page is
> invoking the same function than the first one ?

In my example I only had one form, so the client/server interaction was
like this sequence diagram (you will need a fixed font to see it):


Client                                 Server (flowscript)

open the page w/ the form    --GET-->  function call
:                                       \_ new Form()
:                                       \_ showForm()
:                                           \_ internal validation loop
display the form             <·······           \_ sendPageAndWait()

try and submit the form      --POST->           \_ validation FAILS
redisplay the form           <·······           \_ sendPageAndWait()

try and submit the form (*)  --POST->           \_ validation SUCCEEDS
:                                       \_ DB operations
display the results          <·······   \_ final sendPage()


Read it like this:
  1 ---> 2
         3
  5 <··· 4

The problem is, if the user doesn't get the final results page (for
whatever reason) she will hit refresh and the flowscript will resume
from (*), which is a Bad Thing.

With my addition, the last part of the sequence diagram looks like this:


try and submit the form      --POST->           \_ validation SUCCEEDS
:                                       \_ DB operations
:                                       \_ redirectToGet()
:                                           \_ createWebContinuation()
receive the redirect         <·······       \_ redirectTo()

follow the redirect (*)      --GET-->       \_ return
display the results          <·······   \_ final sendPage()


Any refresh will make the flowscript resume from (*), which is correct.


It seems to me that any non-trivial use of createWebContinuation() needs
a flag variable (var done in my example) and a subsequent test.  Is that
correct?  Am I missing something?


Tobia

---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@cocoon.apache.org
For additional commands, e-mail: users-help@cocoon.apache.org


Re: Redirect at the end of a form

Posted by Baptiste Placé <bo...@free.fr>.
Hi Tobia,

Have you tried stocking form data into a collection, and send it to the 
final page ?
Refreshing the page re-executing the db actions mean the final page 
triggers the DB part of your flowscript.
Maybe your final page is invoking the same function than the first one ?

-Baptiste

Tobia a écrit :
> Cocoon users,
>
> I would like to get your feedback on a piece of flowscript I just wrote
> to solve what I believe to be a common problem.
>
> Suppose you have a form that asks the user for some data, validates it
> and inserts it into a database, using a DB access layer for flowscript,
> such as jdbi.js from the samples.  The basic flowscript would be:
>
> 	// create and show the form
> 	var form = new Form(...)
> 	form.showForm(...)
>
> 	/* execute DB operations to store the newly inserted data */
>
> 	//send a results page back to the user
> 	cocoon.sendPage(...)
>
> The final sendPage() sends a custom page to show the user what he has
> just inserted.  Suppose also that said data does not have a public url,
> but is only available to the submitting user at the end of the form.
>
> What is the problem with the previous flowscript?  If the user reloads
> the final page, the DB operations are executed again, possibly resulting
> in duplicate insertions or other errors.
>
> The usual solution to this problem is to issue a client-side redirect to
> a GET url, so that subsequent client reloads don't have side effects.
>
> Continuations seem the perfect tool to issue such a redirect to a
> private url built on-the-fly for just one user, but I couldn't find an
> idiomatic way of doing it in the samples, so I wrote my own.
>
> The following function is called after the DB operations, just before
> the final sendPage()
>
> 	function redirectToGet() {
> 	  var done = false
> 	  var cont = cocoon.createWebContinuation()
> 	  if (! done) {
> 	    done = true
> 	    var url = /* build a url that will call cont.id */
> 	    cocoon.redirectTo(url, true)
> 	  }
> 	}
>
> What do you think?  Is there a better way of doing it?  How is this
> problem usually solved?  Any feedback is welcome.
>
>
> Tobia
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: users-unsubscribe@cocoon.apache.org
> For additional commands, e-mail: users-help@cocoon.apache.org
>
>   

---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@cocoon.apache.org
For additional commands, e-mail: users-help@cocoon.apache.org


Re: Redirect at the end of a form

Posted by Joerg Heinicke <jo...@gmx.de>.
On 04.06.2007 15:26, Tobia wrote:

>> When the user hits refresh on the confirmation page, the database
>> operations will be skipped and the confirmation displayed again.
> 
> Interesting, I had not thought of putting the flag variable in the main
> flowscript function.
> 
> Although one advantage of the redirect is that the user can refresh
> smoothly, without any warning message.  In some browsers, when you
> refresh a page that was gotten through a POST, you get an alert about
> resending the form data.

And what happens when he uses the browser's back button? Don't you end 
up executing the db operations again? That's why I don't like that 
"pattern". It fixes one particular symptom but not the actual issue. IMO 
only invalidating the continuation helps. But then I wonder how one 
could claim "continuations are fixing the browser's back button" since 
you actually disable it. I might overlook something but it seems both 
can't address the issue completely.

Joerg

---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@cocoon.apache.org
For additional commands, e-mail: users-help@cocoon.apache.org


Re: Redirect at the end of a form

Posted by Tobia <to...@linux.it>.
Jason Johnston wrote:
> When the user hits refresh on the confirmation page, the database
> operations will be skipped and the confirmation displayed again.

Interesting, I had not thought of putting the flag variable in the main
flowscript function.

Although one advantage of the redirect is that the user can refresh
smoothly, without any warning message.  In some browsers, when you
refresh a page that was gotten through a POST, you get an alert about
resending the form data.


Tobia

---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@cocoon.apache.org
For additional commands, e-mail: users-help@cocoon.apache.org


Re: Redirect at the end of a form

Posted by Jason Johnston <co...@lojjic.net>.
Tobia wrote:
> Cocoon users,
> 
> I would like to get your feedback on a piece of flowscript I just wrote
> to solve what I believe to be a common problem.
> 
> Suppose you have a form that asks the user for some data, validates it
> and inserts it into a database, using a DB access layer for flowscript,
> such as jdbi.js from the samples.  The basic flowscript would be:
> 
> 	// create and show the form
> 	var form = new Form(...)
> 	form.showForm(...)
> 
> 	/* execute DB operations to store the newly inserted data */
> 
> 	//send a results page back to the user
> 	cocoon.sendPage(...)
> 
> The final sendPage() sends a custom page to show the user what he has
> just inserted.  Suppose also that said data does not have a public url,
> but is only available to the submitting user at the end of the form.
> 
> What is the problem with the previous flowscript?  If the user reloads
> the final page, the DB operations are executed again, possibly resulting
> in duplicate insertions or other errors.
> 
> The usual solution to this problem is to issue a client-side redirect to
> a GET url, so that subsequent client reloads don't have side effects.

I think there's a simpler way to avoid the double insertions, also using 
continuations but without a client-side redirect:

--------------------------------------
var processed = false;

// create and show the form
var form = new Form(...);
form.showForm(...);

if(!processed) {
     /* execute DB operations to store the newly inserted data */
     processed = true;
}

//send a results page back to the user
cocoon.sendPage(...);
--------------------------------------

When the user hits refresh on the confirmation page, the database 
operations will be skipped and the confirmation displayed again.

WDYT?

> 
> Continuations seem the perfect tool to issue such a redirect to a
> private url built on-the-fly for just one user, but I couldn't find an
> idiomatic way of doing it in the samples, so I wrote my own.
> 
> The following function is called after the DB operations, just before
> the final sendPage()
> 
> 	function redirectToGet() {
> 	  var done = false
> 	  var cont = cocoon.createWebContinuation()
> 	  if (! done) {
> 	    done = true
> 	    var url = /* build a url that will call cont.id */
> 	    cocoon.redirectTo(url, true)
> 	  }
> 	}
> 
> What do you think?  Is there a better way of doing it?  How is this
> problem usually solved?  Any feedback is welcome.
> 
> 
> Tobia
> 
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: users-unsubscribe@cocoon.apache.org
> For additional commands, e-mail: users-help@cocoon.apache.org
> 


---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@cocoon.apache.org
For additional commands, e-mail: users-help@cocoon.apache.org