Blog

Thoughts from my daily grind

Toastr Flash Messages with Turbo, Stimulus & Ruby on Rails

Posted by Ziyan Junaideen |Published: 11 March 2022 |Category: Ruby on Rails
Default Upload |

The Toastr plugin is one of my favourite pre-built plugins for displaying alerts for users. I often use Toastr alerts alongside usual flash messages (ex: Bootstrap alerts) on single page applications or remote forms.

Since Rails 7, I started coupling Toastr with Turbo and Stimulus. This article explains how to show Toastr alerts using Turbo and Stimulus in a Rails project. I assume you have already installed the Toastr plugin either through yarn add toastr or pinning it through import maps.

Background

The alert will come as part of the form submission. We will send a turbo-stream including the flash message to the client-side. The flash message will point to a Stimulus controller (FlashController) which will in turn fire the Toastr flash message and also auto traditional flash message.

Instruction

I structure my application using Trailblazer Cells, Operations and Reform. This is my Flash component. Think of these as the flash partial and a corresponding helper module.

module JDeen::Cell::Marketing
  class Flash < Trailblazer::Cell; end
end
#flash-container
  - model.each do |key, value|
    .alert.alert-dismissible.fade.in[
      class="alert-#{key}"
      role="alert"
      data-controller="flash"
      data-flash-type=key
      data-flash-message=value
    ]
      button.close aria-label="Close" data-dismiss="alert" type="button" 
        span aria-hidden="true"  = value

In the Slim file, for each alert, we have defined data-controller, data-flash-type and data-flash-message attributes. The data-controller is to specify the Stimulus controller and the others are there to easily extract flash details.

This is the Stimulus controller that will handle the flash messages. I am going to auto dismiss the flash messages in 5 seconds and also create Toastr alerts for each flash message.

// app/javascripts/controllers/flash_controller.js

import {Controller} from "@hotwired/stimulus";
import toastr from "toastr";

export default class extends Controller {
  connect() {
    let type = this.element.dataset.flashType;
    let message = this.element.dataset.flashMessage;

    // Auto remove the flash messages
    setTimeout(() => {
      this.element.remove();
    }, 5000);

    // Create Tostr flash messages
    toastr[type](message);
  }
}

We now have what it takes to show the flash messages. How do we deliver the flash messages to the client side? In the old days, we would have used a JSON response or JS responses to achieve our goals. But today we can entirely rely on turbo streams.

This is a simplified controller for posting comments for my blog posts.

# app/controllers/marketing/posts/comments_controller.rb
class Marketing::Posts::CommentsController < ApplicationController
  # ...

  def create
    respond_to do |format|
      flash.now[:success] = "Thank you #{context[:model].user.name} for your comment!"

      format.turbo_stream do
        render turbo_stream: [
          # I am using Trailblazer on top of Ruby on Rails. This is similar to
          # rendering a partial. You may use `partial: 'layouts/frontend/flash'`
          #  kind of approach to render the partial.
          turbo_stream.replace(
            "flash-container",
            html: cell(JDeen::Cell::Marketing::Flash, flash)
          ),

          # Turbo frame to render a new form

          # Turbo frame to append the new comment
        ]
    end
  end

  # ...
end

We are rendering a turbo stream. That is basically a set of turbo frames. Among many other activities, we may need to do, we are particularly interested in replacing the contents of the flash component. To replace components we use turbo_stream.replace().

Note: Turbo by Hotwire has many actions in addition to replace used above. They are append, prepend, replace, update, remove, before and after. More details about Turbo Stream Actions

That is it, now you will have a form submission that will not only display a traditional flash but also fire a Toastr alert.

About the Author

Ziyan Junaideen -

Ziyan is an expert Ruby on Rails web developer with 8 years of experience specializing in SaaS applications. He spends his free time he writes blogs, drawing on his iPad, shoots photos.

Comments