Using Flash With Ruby on Rails Validations

In this blog post, I want to briefly discuss an invaluable tool included in the default Rails tool kit for displaying validation errors in web app views: flash messages.

So, what are flash messages in Rails? As per the Ruby on Rails documentation, flash acts as a middleware to pass information between HTTP actions. Furthermore, flash is a method that will save strings, arrays, or hashes in the next full-page reload of a browser.

In other words, Rails provides a rudimentary system (without the introduction of cookies) for passing information between stateless HTTP requests via flash. However, after the next HTTP request (directly following the original session wherein the data is collected) flash will automatically clear the information.

Upon first glance, flash can seem a bit complex, but with a few practical examples its abstractions are not only understood but greatly appreciated.

FLASH IN PRACTICE

  1. Call flash and assign a string, array, or hash to a key (i.e. flash[:key] = “…”).
  2. Redirect or render a new page (thus triggering a new HTTP request) in the controller
  3. In the view file, check to see if flash[:key] has any values stored, and if so render the value(s) stored in the flash key.

Let’s put our words into practice, and show a simple example of this process with some actual ruby:

# app/controllers/tests_controller.rbclass TestController < ApplicationController    def index        flash[:test] = "this is a flash message!"    endend

Here we store use the default ApplicationController, from which TestController inherits flash, to render an index page. We use flash to store the string, “this is a flash message!” with the key test.

Then, Rails will automatically render the index page:

# views/tests/index.html.erb<h1> This is the index page! </h1><% if flash[:test] %>    <%= flash[:test] %><% end %>

The index page will show us the message stored in flash[:test] (using ERB templating), so long as there is indeed something stored in flash[:test].

RAILS VALIDATIONS

But first, what are validations, and why use them at all?

Rails validations help ensure that objects are of a certain state before they enter your database. It is important to use validations as they ensure that only data that will work with your model’s logic enter your database. This way, one need not fret about endless edge cases in one’s controller and views and can build a web app’s logic with the security of having consistent, bug-free data.

For instance, imagine you are designing an e-commerce app and you want sellers to input the name of their store, which you will then add to your database. What if the user just submits a blank form? Or types a long, unrealistic store name? Or even tries to create a knock-off store with the same name as a competitor? If these invalid values are stored in the database, they could cause innumerable bugs later down the line when trying to display data in one’s views.

Using Rails’ model-level validations prevents these errors from happening in the first place, ensuring only valid data is entered into the database. In our example, we could make only non-blank, unique, concise store names valid with Rails. Let’s see what that would look like in actual code:

# app/models/store.rbclass Store < ApplicationRecord    validates :name, presence :true, uniqueness: true, length: {         maximum: 30 }end

Thus, the name attribute of the store model will always have to be a non-nil value, a name that is not already in the database, and have a maximum length of 30 characters.

TYING IT ALL TOGETHER: VALIDATIONS WITH FLASH

#app/controllers/stores_controller.rbclass StoresController < ApplicationController
def new @store = Store.new end
def create @store = Store.create(store_params) if @store.valid? redirect_to store_path(@store) else flash[:errors] = @store.errors.full_messages redirect_to new_store_path end end
private
def store_params params.require(:store).permit(:name) endend

Here, in our stores_controller, we set up a very basic system for creating a store. First, a user makes a get request to /stores/new, which is then routed via new in the controller. Then, the user fills out a form to create a store, and makes a post HTTP request via the create route. We have created a private method to ensure that users cannot tamper with the params hash, store_params, (learn more about strong params), and use store_params with ActiveRecord’s #create method.

REMEMBER — ActiveRecord’s #create method attempts to both instantiate and save a new store object to the database. In this process, Rails will run validations on this new instance and will only save it to the database if it is valid. ActiveRecord’s #create will always return false, so next we use the ActiveRecord’s built-in #valid? (which runs validations again, returning true if all validations pass and false otherwise) to get a true/false value.

If the new store instance (with the user’s input data) is valid, the user is redirected to the store’s show view (which we did not code here) but if not, we again use flash.

We use flash to store all of @store’s errors with their full messages and afterward redirect the user back to the new route. Since flash will save the data for one HTTP action (sending a get request in the new form), we now can show the user exactly which validations failed in the store’s new.erb!

#views/stores/new.erb<% if flash[:errors] %>  <ul>    <% flash[:errors].each do |error| %>      <li> <%= error %></li>    <% end %>  </ul><% end %>
<%= form_with model: @store do |f| %> <%= f.label :name %> <%= f.text_field :name %>
<%= f.submit %><% end %>

We lastly use a simple form_with helper to generate a form to enter the store name. If the user inputs any invalid data — thus making flash[:errors] contain something and return a truthy value — each of the errors in an unordered list (list of bullet points).

You don’t even have to worry about the error messages themselves, as if one uses built-in ActiveRecord validations the error messages have default values — talk about Rails magic!

Anyhow, I hope that this blog has illuminated flash’s usefulness when dealing with Rails validations — best of luck with your RoR ambitions!