Back in a Flash: Using Flash Messages in your Ruby on Rails apps
Here, we’ll focus specifically on its capabilities within Ruby on Rails and how you can employ flash within your fullstack apps.
Statelessness (or: Help, I’m Lost and Can’t Find my Way out of the Internet)
The internet (or IP) as it exists today has been built to be stateless: i.e., it doesn’t retain information by either the client or the server. Separately and similarly, HTTP (hypertext transfer protocol) is also designed to be stateless. Some protocols that are stateful, on the other hand, include TCP (transmission control protocol) and FTP (file transfer protocol).
The reasoning for statelessness is that a significant amount of storage would need to be allocated to track the information related to every conversation in process, and then further, a process designed to remove those finished or canceled sessions which would otherwise still be saved. By doing so, the speed at which every full-page reload occurred would be drastically diminished. Think of it this way: if Twitter had to remember every session for every one of it’s 326mm active monthly users, on top of the 500mm new tweets created every day, …it would be a giant, slow behemoth of an application. Definitely slower than Limewire and sloths.
A quick aside: the internet layers stateless and stateful protocols on top of each other: IP lays the foundation, then TCP, then HTTP on top. Other protocols can be layered above HTTP, but HTTP itself has workarounds (again: cookies) to persist session data.
FLASH: What, Where, and How
Per the Rails Docs, flash is a middleware method that sends forward temporary datatypes which the Rails controller delegates to the request object. Now in plain English: flash is a method through which you can send a temporary string, array, or hash once between your otherwise stateless HTTP requests. In the next full-page reload, the temporary data that you sent into the future can be brought forward and manipulated or rendered, and then thereafter cleared in the following full-page reload. To be clear, flash data is only available to the original session where the data is collected and the one directly following.
In order to implement flash in your own apps, there’s a specific set of steps that must be taken.
- You first call and set flash in your action controller. You must tell flash precisely what you want it to persist forward.
- Redirect your action controller to the full-page reload of your choice.
- If you want to display that saved data in the rendering of your chosen full-page reload, you first confirm if anything has, in fact, been sent forward through flash, and then iterate through the available data in order to display it in the browser.
Through these steps, you can temporarily persist data forward to the client. The most common use for flash that I’ve seen thus far is to render error messages (did you actually enter a valid email?). Each time you ask a client to complete a form with validations and they fail to complete it accurately, your page would otherwise re-render and lose that error data if you didn’t persist that information in flash.
Putting Flash to Work
Before we dig into rendering error messages with flash, let’s first walk through a simpler example.
#app/controllers/wonkas_controller.rb1 class WonkaController < ApplicationController
2 def index
3 flash[:snozberries] = "The snozberries taste like snozberries!"
So here, we have a Wonkas Controller, which is inheriting from the larger built-in, Application Controller. We’ve defined an action, index, that is assigning the string, “The snozberries taste like snozberries!” to flash with the symbol of
:snozberries. This string is the data that we’re asking flash to persist. Next, we have to actually call the flashed data into a view.
1 <h1> Welcome to the Chocolate Factory </h1>
3 <%=flash[:snozberries] %>
Here in our index view, we’re simply setting a title, “Welcome to the Chocolate Factory” and then calling the flashed data. That’s it!
Now, perhaps you’d like to persist some error messages. One of flash’s built-in convenience accessors is
errors (along with
notice). In this example, we’ll validate some of the attributes for a model, which can create errors when the client doesn’t create a valid instance of the model, parse those errors into flash, and render those flashed errors to the client when it reloads the form to create an instance.
In this example, we have some dogs — maybe Labradors, perhaps Great Danes, but maybe also …Dalmatians.
class Dog < ApplicationRecord
belongs_to :breedvalidates :name, uniqueness: true
We have a
Dog class that belongs to
Breed and our model will validate that every new
dog instance must have a unique name. Now, if we shift our view to the
dogs_controller, you can see that we have a method here to create a new
dog form and to then create a new
dog instance. The
new action will not only create a new dog instance for the
create action to validate, but also call upon all of the
breed instances so that it can select a breed to associate with a
dog. In the
create action, we’re confirming that the new
dog instance is valid, and if it is, creating and redirecting to the new instance’s
show rendering (via the
dog_path for that
dog instance). If the new
dog instance is not valid, it saves the associated errors into flash and reloads the form to create a new
#app/controllers/dogs_controller.rb1 class DogsController < ApplicationController
2 def new
3 @dog = Dog.new
4 @breeds = Breed.all
7 def create
8 @dog = Dog.create(dog_params)
9 if @dog.valid?
10 redirect_to dog_path(@dog)
12 flash[:errors] = @dog.errors.full_messages
13 redirect_to new_dog_path
19 def dog_params
20 params.require(:dog).permit(:name, :age, :breed_id)
Here in our
new.erb view, we are here confirming that there is data saved within
flash[:errors], and then iterating through each of the errors (as many as exist — see lines 2–4) and then printing them to the page (line 3).
Next, we’re simply creating a form with the form_for helper so the client can create a new
dog: a name, an age, and a breed from the
Breed model. Here, we can see a
collection_select method that is allowing us to create a dropdown so the client can select one of the available breeds.
In the event that the client creates a dog that cannot be validated, the errors that are created will be rendered in the
new view for only the next full-page reload. In this case, our
create controller reloads the page when the
dog instance is not valid.
#views/dogs/new.erb 1 <% if !!flash[:errors] %>
2 <% flash[:errors].each do |e| %>
3 <p><%= e %></p> <br>
4 <% end %>
5 <% end %>
7 <%= form_for @dog do |f| %>
8 <%= f.label :name %>:
9 <%= f.text_field :name %><br>
10 <%= f.label :age %>:
11 <%= f.number_field :age %><br>
12 <%= f.collection_select :breed_id, @breeds, :id, :name %>
13 <%= f.submit %>
14 <% end %>
Now that you’ve seen flash in the wild, you can utilize flash for your own apps and display temporary flashed data to your clients. Further resources about flash are included below for your edification.
Good luck out there, and happy coding!