Flash Scope CFC

If you've ever used Grails, you probably know about the 'flash' scope that it provides for passing data from one request to the next.  Certainly not a must-have feature, but it's quite handy.  The typical use case is after a form submit, you set stuff into the flash scope and then redirect to some page where you use the flash scope's contents to spit a message back to the user.  For example, after editing a user and submitting, you'd redirect the browser to the user listing page and display a "Successfully updated user" message at the top of the page.

The benefit of using the flash scope for doing this is that it only lasts one request, so if the user refreshes the listing page, they won't see the success message again (nor should they, since a user wasn't updated on the refresh).  It also keeps your URLs clean (because you don't have to pass stuff along on the query string), and lets you pass complex data (since there is no serialization).

I'm sure a lot of people have faked this functionality in some sort of use-specific way, and I know I'm guilty.  However, after preparing to do it yet again, I thought I'd build a more generic mechanism that I could reuse.  Before I give you the actual code, here's how you might use it:

<cfcase value="onRequestStart">
  <cfset flashScope = createObject("component", "FlashScope") />
</cfcase>

<cfcase value="updateGoal">
  <cfset xfa.success = "goalList" />
  <cfset goalService = request.beanFactory.getBean("goalService") />
  <cfset goalService.updateGoal(
    session.user.getId(),
    attributes.id,
    attributes.name,
    attributes.definition
  ) />
  <cfset flashScope.put("message", "Goal Updated Successfully!") />
  <cfset location("#self##xfa.success#") />
</cfcase>

<cfcase value="goalList">
  <cfset goalService = request.beanFactory.getBean("goalService") />
  <cfset goalList = goalService.getGoals(session.user.getId()) />
  <cfif flashScope.has("message")>
    <cfset statusMessage = flashScope.get("message") />
  </cfif>
  <cfset include("dsp_goallist", "bodyContent") />
  <cfset do("lay_auto") />
</cfcase>

As you can see, we're instantiating the flash scope at the start of every request.  Then in 'updateGoal', the 'message' key is set into the flash scope.  Finally in 'goalList', if there's a 'message' in the flash scope, it is set into a local variable (to be emitted within dsp_goallist.cfm).  Pretty straightforward.  The actual mechanism is a pair of structures: one in the request scope for incoming variables and one in the session scope for outgoing variables.  The FlashScope CFC is nothing more than a facade to those two structures.  This implies that you must have the session scope available to your application, of course.

I haven't created a full-on project for this but it garners sufficient interest and development activity, I'll certainly do that.  In the meantime you can view/download the CFC (or if you're using Subversion, svn:externals it into your project).

In the interest of full disclosure, I want to call out two shortcomings in the implementation, both of which are intentional (to minimize complexity):

  1. There is no respect paid to dealing with concurrent requests.  They'll happily intermix their variables in the flash scope, potentially causing errors and/or bizarre behaviour.
  2. The scope isn't really tied to the 'next' request, it's tied to the 'next request that reads the flash scope'.  This can yield behaviour if your app assumes that the flash scope will be consumed, but it isn't for whatever reason.

Both of these would require some sort of nonce on every request, which adds a whole layer of complexity and necessitates passing some sort of request parameter on the URL or whatever.  That's a) a mess, b) complicated, and c) application-specific.  As such, I've opted to intentionally not handle those cases since they're edge cases and I'd rather keep things simple.  That and I have this inexplicable obsession with 80-100 line, single-file microframeworks (see FB3lite, CFGroovy, TransactionAdvice, etc.).  :)

3 responses to “Flash Scope CFC”

  1. Mike Henke

    I wonder if most coldfusion frameworks have something like this built in. CFWheels does http://cfwheels.org/docs/chapter/using-the-flash

  2. Charlie Griefer

    ColdBox has a flash scope as well. Not sure about any of the other CF frameworks.

    Now I'm kind of curious about how similar/different the 3 are in their implementations. I think it's definitely nice to have a CFC available for projects that don't require a framework (or for folks who don't use 'em)… but wondering about how similar the implementations between them are.

    Could it be worthwhile to "standardize" on a single community-supported flash scope that can either run as a CFC or be injected into any of the popular frameworks?

  3. Matt Osbun

    Very cool. I used to do this with Mach-II. Had a Flash plugin that looked for a struct in session scope. If found, it moved the contents to the request scope and enptied the struct.

    Calling it Flash confused a few people. I meant it in the Rails sense, it usually got interpreted as if I was using Adobe Flash. :)