Flash Ram Problem

Hi,

I really like the flash ram functionality of coldbox, but i have one
problem, if i persist variables from event.action1 to event.action2,
then if i refresh the page at event.action2, the persist variables are
gone.

I didnt expect this behaviour.

I found this solution:

- in event.action2, immediately persist the same variables in the top
of the event, so at a refresh they are still there. This has the
disadvantage that if event.action2 goes to event.action3, action3 will
have these variables too, but it doesnt really matter though.

I dont like it though, because i always have to think about this and
code it, and i wish there was an automatic way the persisted variables
stay there with a refresh.

What can i do to solve this in a way so that always the persisted
variables are there also after a page refresh?

greets,
klaas-jan

In my opinion, the behavior is exactly as it should be. Event variables are meant only for a specific event (request). They are not meant to hang around for more than a single request.

The framework should not be the one in the driver’s seat in determining which variables go into which scopes or which events; all of that is for the developer to decide. By allowing for the “flash memory” between events, the framework offers more flexibility to the developer, and that feature is certainly one of my favorites (since I suggested it… heh), but it is still up to me to do with those “flash memory” variables what I need done with them. In no way would I ever be willing to give control of those to the framework.

If you have a chain of events that are all related to one another, like in a wizard type of scenario, I would recommend considering some other sort of memory usage. Perhaps place the variables into a session container? And if Event B requires a variable from Event A, I would certainly put a check into place that verifies that the variable exists. If it doesn’t, send the user back to Event A.

HTH

Another option that I forgot to mention is paramValue(). Let’s say that Event A creates a variable named ‘foo’, and foo’s value must be a number. You might do something like the following in Event B:

event.paramValue(“foo”, “”); // make sure the variable exists

if ( NOT isNumeric(event.getValue(“foo”)) ) {
// ooops, it’s not a number, so send them back to Event A
setNextRoute(“handler/EventA”);
}

HTH

Well, you don't need the event.paramValue.

You could just write:

if ( NOT isNumeric( event.getValue("foo",'') ) ) {
     // ooops, it's not a number, so send them back to Event A
     setNextRoute("handler/EventA");

Klaas-Jan,

Why don't you use session storage?

Groetjes,

Ernst

So, i cant see any useful use for flashram anymore actually? Can you
guys give me an example?

What i meant is:

In the coldbox examples and documentation, it suggest flash ram as an
alternative to passing things through the url.

The thing is, if you pass it through the url, a refresh is now
problem, it will just re-execute the page.

By the flash variable dissapearing i feel im getting very unusual
behaviour of my web pages, and sending a user back to the previous
event, i also have to send all the form data back to that event, that
is not an option.. thats even more coding and its a solution for
something i feel should be done differently in the first place.

So this is why i wonder, for what do you guys use flashram?

The session is indeed a solution, but now i have stuff persisting
until the end of the session, which i dont want either.

The ideal solution would be to have a Conversation state, as they use
in the Java libary "Spring Web Flow".

greets,
klaas

There are an infinite number of great examples of its usefulness. Here are a couple of quickie examples, all rolled up into one scenario.

Event A is a “Contact Us” form. It submits to Event B. Event B validates the form fields, and if successful, sends the user to Event C which displays a message confirming that the contact for was successfully submitted. However, if the validation fails, you want to send the user back to Event A with the appropriate error messages. This scenario provides two examples of where the “flash memory” can (and should, imo) be used:

  1. If the validation is successful, you can use the “flash memory” to “remember” their name between Event B and Event C, displaying a personalized message.

Hi #event.getValue(“firstName”)#, thank you for contacting us. A representative will be in touch with you soon.

  1. If the validation fails, you can use the “flash memory” to “remember” all of the form values so that the form is populated with the values the user entered.

Why would stuff persist until the end of the session? The only way that would happen is if the developer did not destroy the variable prior to the session timing out.

structDelete(session, “myVarKey”);

Out of curiosity, how would you propose the framework know where to place “flash memory” variables and for how long to keep them?

Given the poor example that I gave, then no, the paramValue() is not needed. My point wasn’t in using paramValue() to check something, but rather that paramValue() should be used to be guaranteed that the value exist. :wink:

Hi matt,

Ive been thinking about it, i think the essence of what i am missing
from the FlashRam of coldbox, is that it cant deal when the user uses
the refresh and backward/forward buttons of the browser.

Example:
action1 persists some variables (they are complex variables, cant go
through url without serializing) and displays a form
the form posts to action2
action2 adds the form variables to the persisted variables and shows a result.

Now, if you refresh action2, it will throw an error, the persisted
variables are gone.
OR: If you go back to action1 with the browser back button, and press
the submit button again, it still goes wrong.
the only way to recover from this, is to press refresh on action1.

They way i see it, there are no solutions except from using the session scope.

This is an age old problem for any web developer.

I hoped, but actually did not really expect, that the Coldbox
developers made something really smart, but i think i it was a false
hope :).

Now the session scope solution:

This solution can also go wrong. Say:

action1 persists (complex) variables
action2 adds to these variables,
action3 adds to these variables.

No the user presses back twice and presses submit again, now action2
will add to the variables of action3.

See that action3 adds a firstname to a cfc that contains a user,
action2 displays the complete user, but it will show
the added firstname of action3. This is an error.

The way i see it there are only two solutions (when you dont want to
use the url):

* To any form, add a unique identifier (GUID?). We persist variables
under this GUID in the session (in a structure for example). Because
this GUID is always in the form variables, we can always get the
persisted variables back. Basically, using this solution, the page
stores the current state in a form variable. I think Microsoft ASP
.NET, works like this.
   -> The problem here, is that you always have to take care that that
GUID is in the form.

* This solution i like best, its implemented within J2ee/Java with the
Spring Web Flow Libary. J2EE has the same storage scopes as Coldfusion
(not a coincidence :):

- request (lasts to short)
- session (lasts to long)
- application (not for one user)

What spring web flow adds is this scope

- conversation

A conversation is a bunch of actions (like an event handler action)
that work together, the start action makes the scope, the stop action
ends (destroys) the scope. When an action between the start and stop
action is re-executed, it also retrieves the old state of that action.
So everytime an action is executed, a state specifically for that
action is saved. So if the user presses back, the old state of that
action is retrieved from the scope.

Now spring web flow implements this a lot more complicated as it also
can take sub-conversations, amongst others. spring web flow also can
persist conversation scopes between sessions.

Im thinking of making a simple conversational scope for coldbox. If
might send another message to this thread when i have this more
concrete.

greets,
klaas

Klaas-Jan,

Why not use hidden form fields? This will solve your refresh problem.
Put rc variables read from action1 into hidden form fields in action 2 etc.

Ernst

What you are describing is what I call a “wizard”. The way I typically handle it is that on the “start action” (to steal your term) an object is set into the session scope and is fully instantiated, with default values set for all variables. This object will contain all getters/setters for all of the variables needed throughout the wizard. Each action throughout the wizard will use this object to grab the values from for populating the forms.

If the user is hitting a particular event for the first time, the default values will be loaded, since that is what the object is populated with. When they submit the form (e.g. click ‘Next’), the form values are grabbed from the request collection and then placed into the object via the setters. If they’re returning to the event after having already submitted it at least once, the form will be populated with the values that they used on the last submit.

When the “stop action” (stealing your term again) is submitted and the wizard is “finished”, the session variable is destroyed.

In other words, what you’re describing is totally available and is done all the time, but it is left up to the developer to set up. I just don’t see how that type of control can be handed over to the framework. Perhaps a “WizardHelper” plugin can be written that will provide helper methods to do this sort of thing, but I still cannot see a framework handling all of that. There are far too many variables to the scenario, in my opinion.

Does any of that make sense?

Yes, indeed, you could call it a wizard, and what you are explaining
is exactly what im trying to do.

But you forgot one thing. Say you have 3 steps, with 3 submit buttons,
next1, next2 and next3.

Every step adds values to your instantiated object with getters and setters.

So say a user pressed next3, which adds values to your instantiated object.

Now the user for some reason pressed 2 times back, and presses next 1
again. Now the values of the form
are added to the instantiated object that still contains the values of
added after the next3 submit button.

You might want this, or not, i dont want this, i think the user would
be suprised and he wouldnt expect those values
from the next3 button to still be there.

klaas

Because i have quite a complex structure of reactor objects with
filled iterators that i do not want to turn into hidden form fields,
i would somehow have to encode/serialize those reactor objects into
hidden form fields. I just had the feeling this is not the right way
of doing it, and just as much work as making a 'conversational scope'.

I’m not forgetting anything. What you’re wanting is so simple, but it seems that you are so thrown by a framework behavior being different than what you thought it would or should be that you’re unable to see the forest through the trees. If/when the user hits their back button and resubmits Next2 you want to make sure that the values for Next3 are empty, simply reinit those values in the wizard object.

So when i change the things i add after next 3, i have to also change
the things i remove in next 2 ?
i dont like that really, its so easy to forget, makes application less
mantainable.

And to what do i reset them? I would have to get the default values
from before next 1...

Klaas, it has become painfully care that nothing I suggest (or likely anyone else) short of the framework doing all of your work for you is going to work. As such, I am removing myself from this thread.

*painfully clear (not care)