How to use SweetAlert2 for your Rails +5.1 (rails-ujs) confirms without jQuery

TL;DR see this demo project for the final solution.

Please be aware that the examples here are provided with ES6 syntax. There are different ways to get ES6 to work in Rails. The demo project has an ES5 branch for reference.

If you are reading this I assume you are familiar with Ruby on Rails and SweetAlert2. With Rails before version 5.1, when rails-ujs was still jquery-ujs, there was an easy way to hook up SweetAlert (or SweetAlert2) with the Rails confirm functionality.

One way to achieve it was to overwrite the confirm handler of Rails:

The old version (jquery-ujs) of overwriting the Rails confirm with SweetAlert2

We had this solution in one of our apps and I wanted to use the new rails-ujs. My first thought was, that it should be an easy task to adapt. Just change $.rails. into Rails. and we’re good:

The naive transformation for the new rails-ujs (doesn’t work)

As it turns out some things have changed.

Rails.handleConfirm can be overwritten, but that will not override the event listener that is already attached since rails-ujs was initialised. But no problem, let’s just write our own event handler and plug it into the new rails-ujs way of doing things. If you have a look at the source code of the start part of rails-ujs you see how event listeners are created. The code to add an event listener for our own method then looks like this:

Alright, cool. It works for links with the attribute data-confirm-swal="Are you sure?" now 🎉 … but wait, if you have a delete link, the confirm dialog never shows up because the method never gets called. 🤔 Turns out the event listener for method: :delete is called earlier because it got initialised before our event listener for SweetAlert2. This is because the event listeners of rails-ujs are hooked up directly when evaluating the code.

If we want to add our event listener by requiring our Javascript code before rails-ujs, then we get into the Problem that Rails.delegate is not defined yet. When you require rails-ujs this is what’s happening:

  • Define event handlers and Rails.delegate
  • Fire rails:attachBindings event on document
  • Attach event handlers ( Rails.start)

So in order to get in between the definition of Rails.delegate and the execution of Rails.start we have to attach to the rails:attachBindings event. (For that to happen we need to require our script before rails-ujs!)

This has to happen before requiring rails-ujs!

🎉 Now everything works as expected 🎉

Final solution

For the final solution have a look at this demo project (with ES5 and ES6 version) or see the code below (only ES6).

To find this all out it took me some hours as I wasn’t familiar with the codebase of rails-ujs. But I learnt a lot along the way. Hopefully with this writeup I can help some other developers as well who want to use the latest version of Rails with SweetAlert2 and without jQuery.

If you use Webpacker, there is an easy way to get in between the rails-ujs code and the start script:

rails-ujs and SweetAlert2 confirm with Webpacker

Hi there, we’re store2be, a Berlin based startup that builds a SaaS enabled marketplace for short term retail space. If you like what we are posting you might wanna check out the store2be tech page or follow our Medium channel.

If you like this post, consider clapping for it 🙌