3.0.0-SNAPSHOT

Using the Flash

Using the Flash to pass data from one request to the next.

The Flash is actually a very simple concept. And no, it has nothing to do with Adobe's Flash Player.

The Flash is just a struct in the session or cookie scope with some added functionality. It is cleared at the end of the next page that the user views. This means that it's a good fit for storing messages or variables temporarily from one request to the next.

By the way, the name "Flash" comes from Ruby on Rails, like so many other cool things in Wheels.

An Example of Using the Flash

The code below is commonly used in Wheels applications to store a message about an error in the Flash and then redirect to another URL, which then displays the message in its view page.

The following example shows how code dealing with the Flash can look in an action that handles a form submission.

function update() {
    if ( user.update(params.user) ) {
        flashInsert(success="The user was updated successfully.");
        redirectTo(action="edit");
    } else {
        renderView(action="edit");
    }
}

Here's an example of how we then display the Flash message we just set in the view page for the edit action. Please note that this is done on the next request since we performed a redirect after setting the Flash.

<cfoutput>
<p class="success-message">
    #flash("success")#
</p>
</cfoutput>

As you can see above, you use the flashInsert() function with a named argument when you want to store data in the Flash and the flash() function when you want to display the data in a view.

The key chosen above is success, but it could have been anything that we wanted. Just like with a normal struct, the naming of the keys is your job.

As an example, you may choose to use one key for storing messages after the user made an error, called error, and another one for storing messages after a successful user operation, called success.

Shortcut for Setting the Flash and Redirecting

The more you work with Wheels and the Flash, the more that you're going to find that you keep repeating that flashInsert()/ redirectTo() combo all the time. Wheels has a solution for that within the redirectTo() function itself:

redirectTo(action="edit", success="The user was updated successfully.");

That piece of code does exactly the same thing as the example shown previously in this chapter. The Wheels redirectTo() function sees the success argument coming in and knows that it's not part of its own declared arguments.

Therefore, you (the developer) must intend for it to be stored in the Flash, so Wheels goes ahead and calls flashInsert(success="The user was updated successfully.") for you behind the scenes.

Prepend with flash for Argument Names that Collide with redirectTos

So what if you want to redirect to the edit action and set a key in the Flash named action as well? Simply prepend the key with flash to tell Wheels to avoid the argument naming collision.

CFScript

redirectTo(action="edit", flashAction="The user was updated successfully.");

We don't recommend naming the keys in your Flash action, but these naming collisions can potentially happen when you want to redirect to a route that takes custom arguments, so remember this workaround.

More Flashy Functions

Besides flash() and flashInsert() that are used to read from/insert to the Flash, there are a few other functions worth mentioning.

flashCount() is used to count how many key/value pairs there are in the Flash.

flashClear() and flashDelete() do exactly the same as their counterparts in the struct world, StructClear and StructDelete—they clear the entire Flash and delete a specific key/value from it, respectively.

flashKeyExists() is used to check if a specific key exists. So it would make sense to make use of that function in the code listed above to avoid outputting an empty <p> tag on requests where the Flash is empty. ( flash() will return an empty string when the specified key does not exist.)

Check out the Controller > Flash Functions section in the API listing of all the functions that deal with the Flash.

Wholesale Flash Handling with flashMessages()

Throw the flashIsEmpty() function into the mix, and you might find yourself writing code across your Wheels projects that looks something like this:

<cfoutput>

<cfif NOT flashIsEmpty()>
    <div id="flash-messages">
        <cfif flashKeyExists("error")>
            <p class="errorMessage">
                #flash("error")#
            </p>
        </cfif>
        <cfif flashKeyExists("success")>
            <p class="successMessage">
                #flash("success")#
            </p>
        </cfif>
    </div>
</cfif>

</cfoutput>

All of that above code can be replaced with a single call to the flashMessages() function:

<cfoutput>
#flashMessages()#
</cfoutput>

Whenever any value is inserted into the Flash, flashMessages() will display it similarly to the complex example above, with class attributes set similarly (errorMessage for the error key and successMessage for the success key).

You can also use flashMessages()'s key/keys argument to limit its reach to a list of given keys. Let's say that we only want our layout to show messages for the alert key but not for the error or success keys (or any other for that matter). We would write our call like so:

<cfoutput>
#flashMessages(key="alert")#
</cfoutput>

Just keep in mind that this approach isn't as flexible, so if you need to customize the markup of the messages beyond flashMessages()'s capabilities, you should revert back to using flashIsEmpty(), flash(), and other related functions manually.

Flash Storage Options

Earlier, we mentioned that the data for the Flash is stored in either the cookie or the session scope. You can find out where Wheels stores the Flash data in your application by outputting get("flashStorage"). If you have session management enabled in your application, Wheels will default to storing the Flash in the session scope. Otherwise, it will store it in a cookie on the user's computer.

You can override this setting in the same way that you override other Wheels settings by running the set() function like this:

//In `app/config/settings.cfm` or another `settings.cfm` file within the `app/config` subfolders
set(flashStorage="session");

Note: Before you set Wheels to use the session scope, you need to make sure that session management is enabled. To enable it, all you need to do is add this.SessionManagement = true to the app/config/app.cfm file.

Choosing a Storage Method

So what storage option should you choose? Well, to be honest, it doesn't really matter that much, so we recommend you just go with the default setting. If you're a control freak and always want to use the optimal setting, here are some considerations.

  • Although the Flash data is deserialized before stored in a cookie (making it possible to store complex values), you need to remember that a cookie is not the best place to store data that requires a lot of space.

  • If you run multiple ColdFusion servers in a clustered environment and use session-based Flash storage, users might experience a loss of their Flash variables as their request gets passed to other servers.

  • Using cookies is, generally speaking, less secure than using the session scope. Users could open their cookie file up and manually change its value. Sessions are stored on the server, out of users' reach.

Appending to, rather than replacing the flash

From CFWheels 2.1, you can now change the default flash behavior to append to an existing key, rather than directly replacing it. To turn on this behavior, add set(flashAppend=true) to you /app/config/settings.cfm file.

An example of where this might be useful:

// In your controller
if( thingOneHappened ){
  flashInsert(info="Thing One Happened");
}
if( thingTwoHappened ){
  flashInsert(info="Thing Two Happened");
}

Which, when output via flashMessages() would render:

<div class=""flash-messages"">
  <p class=""info-message"">Thing One Happened</p>
  <p class=""info-message"">Thing Two Happened</p>
</div>

With set(flashAppend=true), you can also directly pass in an array of strings like so:

msgs=[
   "Thing One Happened", "Thing Two Happened"
];
flashInsert(info=msgs);

In 2.2 upwards:

There are certain circumstances where you might not be using the flash: for example, if you have wheels setup as a stateless API (perhaps in a cluster behind a load balancer) where you're using tokens vs sessions. In this circumstance, you've probably turned off session management, which only leaves cookie as a viable route. But if set to cookie, you always get Set-Cookie being returned, which is unnecessary.

In wheels 2.2 you can now set(flashStorage = "none") which will prevent the creation of the cookie, and also not try and write to a session.

Last updated

Logo