Controllers
Flash
HTTP is a stateless protocol. The server, generally speaking, has no idea if request number 243 came from the same user as request number 236. That’s beautiful and, at the same time, annoying.
Web applications frequently need to persist state between requests. That might mean a shopping cart that follows a user through the online store, but it can be as simple as a status message.
In modern applications users expect feedback. After clicking a delete link, a user expects not just to see the item disappear, but also some "Item Deleted" message. In Rails we handle these messages using the flash
.
Flash as a Hash
Developers often refer to the flash as a hash. Is it? As an experiment, within a controller action, you could try this:
1 2 3 4 |
|
Trigger that method from a browser and you’ll find that the flash is an instance of ActionDispatch::Flash::FlashHash
. When you use flash
, you’re calling a helper method which returns this ActiveDispatch object to you. It acts a lot like a Ruby Hash
, yes, but adds more functionality under the hood.
For our purposes, though, we can think of it as a hash-like object.
Flash Messages
The flash will be our message storage object. Let’s look at how, where, and when to set messages.
The Normal Way
The easiest and most common way to set a message explicitly is in the controller. For instance, in a destroy
action:
1 2 3 4 5 6 7 8 |
|
Common Keys
In this example we used the :notice
key, but you can use any key you want within the flash to hold your messages. It’s just a matter of matching up the setting in the controller with the display in the view template. But a few keys are commonly used based on their implications for the user:
:notice
: "Everything is cool, just letting you know.":alert
: "Something is wrong, but it can probably be fixed.":error
: "Something is really wrong and is probably irrecoverable"
If those don’t feel like a good fit for your application you can make up your own
In the Redirect
The actions where we want to set a flash message are often the same ones that necessitate a redirect. In Rails 3 the redirect_to
helper added options to specify the flash message in the redirect call itself.
Instead of this:
1 2 3 4 5 6 7 8 |
|
We can pass a notice:
argument to redirect_to
like this:
1 2 3 4 5 6 7 |
|
redirect_to
will accept :notice
and/or :alert
keys. If you want to set a custom key, like :error
, you could do it like this:
1 2 3 4 5 6 7 |
|
But, then, what’s really the point? If you’re using custom keys, it’s easier to just set the flash in its own line.
Displaying the Flash
You set the flash message in the controller then you have to display it in the view layer.
It’s generally a good idea to display the flash in your application layout. That way it’s available on every page and you don’t have to remember it in individual view templates.
Specific Keys
The flash
helper method is available in the view just like it was in the controller. A simple ERB injection and hash-style lookup will fetch the data:
1 2 3 |
|
That will display a message stored under the :notice
key.
Adding Conditions
But what about when there is no flash[:notice]
? You’ll get a set of empty <p>
tags, which could look strange in your layout.
In Ruby, if you ask a hash for a key that doesn’t exist you’ll get back nil
. Since Ruby considers nil
to be "falsey", we can write a condition like this:
1 2 3 4 5 |
|
5 lines to display one message? We can refactor it by using the content_tag
helper and an inline condition:
1
|
|
Iterating
If our application uses multiple keys, like :notice
, :alert
, and :error
, then we’d need to do that three times:
1 2 3 |
|
Iteration allows us to reduce the redundancy:
1 2 3 |
|
The condition is no longer necessary because if there aren’t keys in the flash, the iteration will just never run.
Exercises
Use the Blogger sample application to complete the exercises in this section. See the Setup Instructions for help.
The Blogger project already uses flash messages, but we can try a few experiments with ArticlesController
:
- Refactor
update
,destroy
, andcreate
to set the:notice
message in theredirect_to
- Add a message under the
:validation
key when an article fails to validate, then display this key in a dedicated paragraph within the form partial. - Refactor the flash display in the application layout to iterate through all keys.
- CHALLENGE: make it so the
:validation
key is skipped in the top display, allowing it to only show up in the form.
- CHALLENGE: make it so the
- Move the body of your flash messages into the
en.yml
locale file and load them using thet
helper