Scott W. Bradley

in which scottwb thinks out loud

Fork me on GitHub

jQuery Mobile and Rails UJS Method Links

| Comments

Rails UJS and jQuery Mobile do not play nice together when it comes to combining Rails UJS’s handling of non-GET/POST links with jQuery Mobile’s data attributes such as data-ajax, data-direction, and data-transition. This post demonstrates a quick hack you can use to remedy this.

The rails.js file from rails/jquery-ujs does some very cool stuff to let you emulate HTTP methods other than GET and POST. It does this by looking for a data-method attribute on your links. When it finds one, e.g.: data-method='delete', it creates an invisible form to submit a POST with all your link details and a special _method=delete parameter that Rails handles in the backend as if it were a DELETE method. Using the link_to helper, that normally looks like this:

1
<%= link_to "Delete", @post, :confirm => "You sure?", :method => :delete %>

jQuery Mobile loads same-domain links and form submissions via AJAX and provide sexy page transitions. You control how these work by adding data attributes to the <a> or <form> element. One important one, that can affect the correct operation of your page, is the data-ajax='false' attribute. That makes disables the AJAX behavior, and loads the next page from your link or form as a new page. That normally looks like this:

1
<%= link_to "View", @post, "data-ajax" => "false" %>

One important time you may wish to exercise both tactics at the same time is in providing a delete link. You want to use a link to generate a DELETE request via Rails UJS, and you want to redirect to a new page without jQuery Mobile loading it via AJAX. This is how you would attempt that:

1
2
<%= link_to("Delete", @post, :confirm => "You sure?",
            :method => :delete, "data-ajax" => "false" %>

Sorry. That won’t work.

This is because Rails UJS does it’s magic by creating a new <form> to submit when the link is clicked. It doesn’t know or care about the data-ajax attribute, and the form it creates does not have that attribute. Then, when the form is submitted, jQuery Mobile handles it using AJAX by default because the form didn’t specify otherwise.

We need Rails UJS to copy the data-ajax attribute from the link to the form it creates. This is actually a pretty simple fix (hack) to the handleMethod funciton in rails.js. To just one-off this particular attribute, you can do somethign like this:

rails.js.diff View Gist
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
diff --git a/src/rails.js b/src/rails.js
index 06b4e0b..49ff0b2 100644
--- a/src/rails.js
+++ b/src/rails.js
@@ -174,6 +174,11 @@

       if (target) { form.attr('target', target); }

+      var ajax = link.data('ajax');
+      if (ajax !== undefined) {
+        form.attr('data-ajax', ajax);
+      }
+
       form.hide().append(metadata_input).appendTo('body');
       form.submit();
     },

In fact, I’ve committed this patch in a branch on my fork of rails/jquery-ujs.

With this addition, the above combination of :method => :delete and "data-ajax" => "false" work beautifully together. You can imagine doing this for other data attributes you care about such as data-direction and data-transition.

There’s currently an outstanding issue to address this, with some discussion on how to go about this generically. If you would like to see this make it into the main distro, head over to that issue and voice your support.

Comments