Replace Confirm Dialog Box with Sweet Alert in Ruby on Rails 6
In Ruby on Rails Dec 2, 2021
Updated on May 13, 2023
In this post, we will discuss how we can integrate the Sweet Alert 2 library into a Rails 6 application. We will build a simple to-do app, and will replace the default confirm dialog box triggered by links such as delete links, with a sweet alert. We will use Rails 6.1.4.1 and Ruby 3.0.3.
Set Up the Application
We will generate a new application with the --skip-turbolinks
option. We’ll call our application
TodoApp.
From the terminal we type:
rails new ToDoApp --skip-turbolinks
Once the application is created, we change the directory to its folder:
cd ToDoApp
Install and Import Sweet Alert 2
We will install the Yarn package, sweetalert2. In the terminal, we type:
yarn add sweetalert2
We need to import the JavaScript code and the stylesheet into our application.
In the application.js
pack in the app/javascript/packs/
folder, we import the
minified JavaScript file:
import Swal from 'sweetalert2/dist/sweetalert2.min.js'
window.Swal = Swal
We will import the stylesheet in the application.css
file in the app/assets/stylesheets/
folder:
@import 'sweetalert2/dist/sweetalert2.min.css'
Generate a TASK Scaffold
Our app is simple, we have only a Task
resource.
The Task
model has only one attribute: the name. Let’s generate the appropriate scaffold in the
terminal:
bin/rails g scaffold Task name:string
And then we run:
bin/rails db:migrate
We also delete the scaffolds.scss
file that was generated automatically in the
app/assets/stylesheets/
directory, because we don’t need it.
Set a Root Route
Our application requires a root
route, so let’s set it to the Tasks
controller’s
index
action. In config/routes.rb
add this at the top:
root 'tasks#index'
Edit the delete links in index.html.erb
Now, it’s time to replace the default confirm box with sweet alerts. In our index.html.erb
file in the
app/views/tasks/
folder, we have delete
links that, when clicked, trigger a confirm dialog
box. We will remove the data-confirm
attribute, then we will add a :remote
option to make
an
AJAX request, and finally, we will write the code to fire a sweet alert when these links are clicked.
We also add a ‘delete-links’ class to these links, so we can easily select them via JavaScript.
Let’s open the index.html.erb file
and edit the delete
links as explained above:
<%= link_to 'Delete', task, method: :delete, remote: 'true', class: 'delete-links' %>
I also changed the word “Destroy” to “Delete”.
Write the JavaScript Code
In Rails, usually, we put our custom JavaScript files in a subdirectory that we create in the
app/javascript/
folder. Let’s call this subdirectory js
and add a file called
index.js
to it. In this file, we’ll write the necessary code to make Sweet Alert 2 work with Rails.
Finally, we import this subfolder into the application.js
pack, so that this code can be compiled by
Webpack:
import 'js'
Also, in the app/views/layouts/application.html.erb
file, we’ll move the
javascript_pack_tag
from the <head>
of the document right before the closing </body>
tag.
Rails uses an unobtrusive scripting adapter (UJS) that provides helpers to assist in writing JavaScript code. Seems
that when used with Webpack, window.Rails
is undefined. So before we write our code, we must edit our
application.js
in order to define it.
Just add this line after the import statements:
window.Rails = Rails
Now, we open the index.js
file and write the following code:
document.addEventListener('ajax:beforeSend', (event) => {
if (event.target && event.target.className === 'delete-links') {
const taskURL = event.target.getAttribute('href')
Swal.fire({
title: "Are you sure?",
showCancelButton: true
})
.then(event.preventDefault())
.then((result) => {
if (result.isConfirmed) {
Rails.ajax({
type: "DELETE",
url: taskURL
})
}
})
.catch(event.preventDefault())
}
})
We attach an event listener to the custom UJS ajax:beforeSend
event. But we do not attach this event
listener directly to these links, but instead, attach it to the document itself, using a technique called
event
delegation. First, we grab the task URL
and store it in a variable called taskURL
. Then we
present the user with a sweet alert. The alert has a cancel button and a confirm button. After the sweet alert pops,
we stop the execution of the Ajax request, waiting for the user to respond. And if the user confirms they want to
delete the task, we delete it by making an AJAX delete
request to the task URL
that we
stored in the taskURL
variable.
Finally, I want to reload the page after the user deletes a task. In the app/views/tasks/
folder, we
create the destroy.js.erb
file and add this code:
window.location.reload()
And in the Tasks controller, we add the format.js
in the respond_to
block inside the
destroy
method:
respond_to do |format|
format.js
format.html { redirect_to tasks_url, notice: "Task was successfully destroyed." }
format.json { head :no_content }
end
The controller will respond to the AJAX request and reload the page to show the updated list of tasks.
And that's it. From now on, when the user wants to delete a task, a stylish sweet alert pop-up will open instead of the default browser alert.