Custom dialog for data-confirm in Rails

Every Rails developers might be already familiar with data-confirm attribute for a link. It is used to ask for user confirmation before executing the action on behalf of user. Here is one example

<%= link_to "Delete", post_path(post), method: :delete, confirm: "Are you sure?" %>

The generated link looks like this:

<a href="/posts/1" data-method="delete" data-confirm="Are you sure?">Delete</a>

When users click on this link, they will see a confirmation dialog to ask them if they are sure to delete that post. Some developers will wonder how it is implemented on Rails, right? Actually, there is no magic in it. If you look at application.js file in your Rails app, you will mostly see the following line

//= require jquery_ujs

Some developers look at it too quickly and they thought that is jQuery UI library. NO, it is not. This is jquery-ujs (https://github.com/rails/jquery-ujs) and it allows Rails to handle links with custom data- attributes such as data-method or data-confirm. More specifically, it will handle the click events on any links have these attributes and prevent the default action if necessary. You can take a look at this file if you are interested in understanding the logic behind it, https://github.com/rails/jquery-ujs/blob/master/src/rails.js

One thing I don't like about data-confirm is that it uses Javascript confirm method, with the default confirmation dialog of the browsers. There are many fancy and beautiful dialogs out there for us to use, and I think it would be much better if we can integrate them into our application instead of using the default one. For example, take a look at two favorite libraries which I like to use: Bootbox, SweetAlert

In order to do this, we will need to override the event handler of jquery-ujs and handle the event on our own. I created a JS script for doing this (I actually took the idea from a guy on the Internet or Stackoverflow but I forgot the link to that post). You can just copy this script and put this in your application.

//Override the default confirm dialog by rails
$.rails.allowAction = function(link){
  if (link.data("confirm") == undefined){
    return true;
  }
  $.rails.showConfirmationDialog(link);
  return false;
}
//User click confirm button
$.rails.confirmed = function(link){
  link.data("confirm", null);
  link.trigger("click.rails");
}
//Display the confirmation dialog
$.rails.showConfirmationDialog = function(link){
  var message = link.data("confirm");
  $.fn.SimpleModal({
    model: "modal",
    title: "Please confirm",
    contents: message
  }).addButton("Confirm", "button alert", function(){
    $.rails.confirmed(link);  
    this.hideModal();
  }).addButton("Cancel", "button secondary").showModal();
}

Explanation

We first override allowAction method with our own method. This is the method called by jquery-ujs when user clicks on a link with data- attributes. If the link does not contain "data-confirm" attribute, we will just return and let users execute the action as normal. Otherwise, we show the confirmation dialog.

//Override the default confirm dialog by rails
$.rails.allowAction = function(link){
  if (link.data("confirm") == undefined){
    return true;
  }
  $.rails.showConfirmationDialog(link);
  return false;
}

Next, we handle the case in which user clicks on the Confirm button

//User click confirm button
$.rails.confirmed = function(link){
  link.data("confirm", null);
  link.trigger("click.rails");
}

Notice that we set data-confirm attribute to null to avoid recursive loop and then trigger click.rails event to let the default event handler to execute the action

Finally, we handle the function to show the dialog to users.

//Display the confirmation dialog
$.rails.showConfirmationDialog = function(link){
  var message = link.data("confirm");
  $.fn.SimpleModal({
    model: "modal",
    title: "Please confirm",
    contents: message
  }).addButton("Confirm", "button alert", function(){
    $.rails.confirmed(link);  
    this.hideModal();
  }).addButton("Cancel", "button secondary").showModal();
}

In the above script, I use SimpleModal plugin (http://simplemodal.plasm.it/). If you want to use another library, just replace the code starting with $.fn.SimpleModal with your own modal. You would need to pay attention to the logic of handling Confirm and Cancel button to make it work properly although it is pretty straightforward.

That's it. Let's forget boring confirm window and start using your beautiful modal.