February 1, 2015 by Daniel P. Clark

Discovering UJS with AJAX

Having worked with Rails a while I’d heard of UJS as being Unobtrusive JavaScript.  I had thought that it was simply a pattern of writing your JavaScript in a JS file to be called via a method call rather than inline JavaScript within elements in the view.  So I had definitely overlooked the benefit of what UJS is.  In case you didn’t know UJS is actually a plugin that helps implement behavior blocks, but that’s not all it does.

My first real experience discovering the advantage of having UJS was with the GoRails tutorial “jQuery UJS and AJAX” by Chris Oliver (@excid3).  After watching the video tutorial my mind was blown!  I was shocked to see a demonstration where you click a link on your site and it executes a JavaScript file on the client directly from the server.  This opened up so many possibilities for me and I’m quite happy about it.  Be sure to check it out!

Applying What I Learned

Now I wanted to use this knowledge to put off loading things in my website until they were needed.  I had three complex Bootstrap modals that were popup dialogs for various things like sending invites, creating contacts, and a less complex feedback feature.  I was currently loading the html for these as partials within my left nav menu partial.  This caused the load time for just the left nav menu to be over 400 milliseconds.

I removed the render partial commands for the three partials:

Since I did the same things for each partial I will continue by demonstrating only what I did with the Invite partial.

I decided I wanted to have my JavaScript files write HTML directly to a div I placed withing the main template.

Then I created a ujs folder in my views directory and wrote files for each partial like this:

I changed the hyperlinks in the nav menu to no longer call the Bootstrap modal but now act as an AJAX link request.  Changed it from:

to:

The ujs_path you see above is a path helper I made:

So far so good.  But now we need routes to make the paths valid.  So I created routes for it as follows:

And then I dropped in a controller to match:

We don’t need to do anything in the Controller as we’re only going to have the “template”, our UJS JavaScript file, get loaded directly.

And that finished the work that needed to be done.  So I open the website and the nav_left partial now loads in only 40 milliseconds!  That’s right I shaved off 90% of its load time by externalizing those partials into UJS/AJAX calls.  And when testing the links the site ran exactly the same as it had before.  Only now it’s much faster.

So when a UJS/AJAX hyperlink gets clicked it executes the template file directly from the server.  And with rendering partials via the <%= j render(partial: ‘layouts/invite’) %> JavaScript render method it gets the same job done and saves a bunch on car insur…. I mean load time!

Summary

The GoRails tutorials are a great resource for learning some helpful and powerful things.  Check it out and sign up!

As you can see that even when we think we understand what something is, such as believing UJS was just a pattern, it still benefits us to research and verify.  That which you think you know may indeed be something you need to know.  And I’ve barely scratched the surface of what UJS is and what it’s designed for.  More details on UJS is available here: http://www.ujs4rails.com/.  It looks like a fun item to utilize.

There are so many ways this can be beneficial in your projects.  Why waste time loading resources when you can save it for when it’s needed?  I’m happy Chris Oliver took the time to make that tutorial.  And I hope that this was insightful and educational for you as well!

Please comment, share, subscribe to my RSS Feed, and follow me on twitter @6ftdan!

God Bless!
-Daniel P. Clark

Image by Mike Johnston via the Creative Commons Attribution 2.0 Generic License.

#ajax#article#blog#gorails#javascript#js#load time#partials#post#rails#ruby#ruby on rails#ujs

20
Leave a Reply

avatar
4 Comment threads
16 Thread replies
0 Followers
 
Most reacted comment
Hottest comment thread
6 Comment authors
Bryan MetzgerMarc GayleRayKarl SmithDaniel P. Clark Recent comment authors
  Subscribe  
newest oldest most voted
Notify of
McFlyyy
Guest
McFlyyy

Damn. Last post on your ujs4rails link was in 2006
Can it still be something relevant almost 10 years later; a time when we have js frameworks all around the place ?

Daniel P. Clark
Guest

UJS is built in to Rails as a feature. Here’s a much more recent article on UJS as it’s currently used in Rails http://robots.thoughtbot.com/a-tour-of-rails-jquery-ujs including links/dialogs/validations/CSRF.

Many people may choose not to use a front end JS framework, but it’s still great to be able to get a lot of the same things accomplished.

McFlyyy
Guest
McFlyyy

Sorry I trolled a bit on this one.
I subscribed to rubyflow to get hot & new rails stuff; i’m a bit disapointed sometimes. but it is just my plain point of view.

Daniel P. Clark
Guest

It’s cool. This was new to me and I’m sure it will be new to many others. I haven’t taken the time to learn a JS front end framework yet. I’m holding out for Volt since I believe it’s the future to bridging the gap between JavaScript and Rails type frameworks.

McFlyyy
Guest
McFlyyy

JS frameworks are a pain to learn; they suppose you already have some stack very weel built stack behind, when not an industry-class api
I’d like to see Volt bring ruby (at large) further

Karl Smith
Guest
Karl Smith

Dan, excellent idea. So good, I started doing the exact same thing about a year ago. I pulled all my modals into partials and load them vis UJS. The only part I don’t like is if the server is a little busy, it can take a few seconds for the modal to appear. Some users are confused and click the “modal” button several times. Thus I want to show a spinner while they wait and disable the “modal” button. I thought of using an empty modal div structure, then just replacing the .modal-body. But I was also using the modal… Read more »

Daniel P. Clark
Guest

I hadn’t considered a spinner. That’s a great idea. You’ve inspired something similar for me. Let me know what you think. For each modal link that we implement the UJS/AJAX feature we add the class loadable. Then just add this JavaScript and the links are all taken care of:

[/crayon]

Karl Smith
Guest
Karl Smith

Have you been reading my code? Looks exactly like mine, minus disable/enable the the button (link).

[/crayon]

I needed this because some of my users are mad-clickers. If something doesn’t appear instantly, click it again, and again. I would see them click the button 4+ times in the logs. Not a huge deal but if the site comes under heavy load, every little bit counts.

Daniel P. Clark
Guest

Yours is better because it disables the link. Whereas mine merely changes its appearance. I think they work well together.

Daniel P. Clark
Guest

I believe I’ve found a quirk implementing this in UJS “link_to(image_tag …) …)”. If I add a class attribute within the link_to then it fails to do a PATCH request and tries via GET. I believe it has to do with the jQuery listener I wrote interfering with the way UJS is implemented. I don’t believe it’s class related. I changed the CSS selector in my JavaScript listener to $(‘[href^=”/ujs/”]’) and that caused the same PATCH to GET error. I was unable to find away around this. If I were to guess UJS should have a way of monkey-patching behavior… Read more »

Karl Smith
Guest
Karl Smith

No. But now that you mention it, I have just been using GET. Since I wasn’t really supplying data for a update/create I chose GET. Even though it may not check the authenticity_token, I’m not really changing data, and all my users must have an valid session so I figured GET is good enough. But it looks like in your example you are “inviting friends” so I see the desire for PATCH and the passed authenticity_token. But if the modal contains the button (link) that actually initiates the invitation, then I think you could use a GET for the modal… Read more »

Daniel P. Clark
Guest

Yes that makes sense. The modals were originally required in a GET request. So changing my method: :patch and my routes to get should allow the jQuery hook to work. I’d like to figure out sometime what happened in UJS/JS that caused this.

Daniel P. Clark
Guest

I found the solution. In The Rails 4 Way chapter 19.1.3 jQuery UJS Custom Events. They have an event handler ‘ajax:before‘. So substituting click for ajax:before allows UJS to work properly.

[/crayon]

Marc Gayle
Guest
Marc Gayle

Don’t mean to butt in to this discussion gents, but I think I may have a more elegant & simple way to do what you guys are trying to do. Rather than writing custom JS to detect the click event on the button, and then replace it with ‘…loading…’, you could simply just add `data: { disable_with: “Loading…”}` to your `link_to` and while the the form is processing (i.e. waiting for your server to respond) it disables the button/link and replaces it with that ‘Loading…’ message until the operation is done and then reverts it when the operation is complete.… Read more »

Daniel P. Clark
Guest

Thanks Marc! I’ve tried this before. I’m not sure about it reverting though. It worked for page reloads, but I don’t think it reverted for dynamic AJAX responses. It’s been a while so I don’t know the specifics; only that it didn’t work out for me.

Marc Gayle
Guest
Marc Gayle

That’s strange, because I just implemented it in my app and it worked like a charm. Very closely to how Chris shows in the video.

*shrugs*

Just thought I would suggest it, in case you guys missed it by any chance 😐

Ray
Guest
Ray

where does the #inviteModal div come from? Is that in your invite partial? if so, can you provide the sample code block in your blog post? Thanks

Daniel P. Clark
Guest

Yes the div is in the invite partial /app/views/layouts/_intite.html.erb. The invite partial is rather large for pasting here. I’ve got SMS/email/Twitter all built-in within Bootstrap tabs inside the modal. Bootstrap’s modals are well documented here: http://getbootstrap.com/javascript/#modals I’ll include a few lines of the partial file _invite.html.erb: Ruby [crayon-5cbb30ccc350f725929974 class="xhtml"] <!-- Modal --> <div class="modal fade" id="inviteModal" tabindex="-1" role="dialog" aria-labelledby="inviteModalLabel" aria-hidden="true"> <div class="modal-dialog"> <div class="modal-content"> <div class="modal-header"> ... content ... </div> <div class="modal-body"> ... content ... </div> </div> </div> </div> 12345678910111213141516  [crayon-5cbb30ccc350f725929974   class="xhtml"]<!-- Modal --><div class="modal fade" id="inviteModal" tabindex="-1" role="dialog"             aria-labelledby="inviteModalLabel" aria-hidden="true">  <div class="modal-dialog">    <div class="modal-content">      <div class="modal-header">        ... content ...      </div>      <div class="modal-body">        ... content ...      </div>    </div>  </div></div> [/crayon]

Bryan Metzger
Guest
Bryan Metzger

Man I hate to bring up a thread this old, but I was wondering how you would fire this off if you didn’t have access to a link_to helper. I figure it would be done on click with a $.ajax call, but I’m not certain.

Daniel P. Clark
Guest

You can follow the Rails guide for it: http://guides.rubyonrails.org/working_with_javascript_in_rails.html

Also there are JavaScript hooks provided for Ajax calls: https://github.com/rails/jquery-ujs/wiki/ajax