Cool Rails Plugin: Scrooge

I have known about this plugin for a while but only recently had the opportunity to play with it a little. The idea behind it is that when we query the database, most of the time we only need a handful of the columns in a table. Rails, however, runs a "select *" anyway because it doesn't know what you will need. The amount of database overhead can be significantly reduced, however, by only selecting the specific columns that our applications needs. To combat this, Scrooge watches the queries the application makes at runtime and dynamically adjusts the select statements to only include the columns you are actually using. Your first thought upon hearing that is, "what if it makes a mistake or a different path through the code uses a different field?" Well, if that happens, the plugin will requery the row using the id and get the additional fields it missed. It will also make a note of that and get those fields to begin with next time. It is extremely easy to use, too. All you need to do is install it as either a gem or plugin and it starts working for you immediately. No configurations, no code to add...it just works. If you don't like it, just back it out and it is all gone. Piece of cake. Depending on your schema, this could be a large or marginal performance improvement. I expect that in most cases you will see a good performance increase, especially for not having to really do anything to your application. I highly recommend checking it out. Take a look at the project homepage for more details. http://github.com/methodmissing/scrooge/tree/master

jQuery Plugin: Curtain

For a project I am working on, I needed to be able to put a very obvious ajax loading indicator on top of the element being updated via the ajax call.  I wrote a simple plugin that will darken the selected elements and put an ajax loader graphic on them.  All you need to do to invoke it is call: [js]$("#element_to_curtain").curtain();[/js] The only configuration on it right now is for the ajax loader image.  With all the current options, the call looks like this: [js]$("element_to_curtain").curtain({ loader_image: '/images/ajax-loader.gif', loader_height: 100, loader_width: 100 });[/js] If loader_image is an empty string, then the loader image will not be added. The loader_height and loader_width are the size in pixels of the loader image. This is only used to calculate the offsets when placing the graphic in the center of the curtain. If you want to check it out for yourself, you can either visit the project homepage or the github page: http://github.com/paulelliott/jquery-curtain/tree/master

Missing Specification Files?

I have been having problems with unpacked gems throwing up warning messages about missing specification files. It looks something like this: config.gem: Unpacked gem cucumber-0.3.11 in vendor/gems has no specification file. Run 'rake gems:refresh_specs' to fix this. It has been my experience that running rake gems:refresh_specs doesn't fix the problem at all. What I have found to work though is to add a file named .specification into the root of the unpacked gem. In the case of cucumber, I added this file: --- !ruby/object:Gem::Specification name: cucumber version: !ruby/object:Gem::Version version: 0.3.11 require_paths: - lib platform: ruby Adjust the gem name and version for any other warnings you get and they should all go away.

How I Do Javascript in Ruby on Rails

I have been asked recently how I do my javascript in a javascript-intensive production application. There are a number of things to consider when you start rolling out huge amounts of javascript in your application. If you aren't careful, it can become an unwieldy beast very quickly. It comes down to two major things to keep in mind: organize and namespace. To level set, I would like to point out that I am a purist when it comes to javascript. I find that completely separating the html, css, javascript, and server side helps to keep things clean and well designed. I always blast the prototype and script.aculo.us libraries from my projects and I never use rjs templates. I write javascript such that it keys off the metadata in the DOM to operate, so no javascript is ever generated by the server. This makes the javascript easy to test and debug, and forces you to think hard about the design of your client layer. I believe that it has helped me to produce a higher quality of code and I continue to use and refine my process.

Organize Your Scripts

It is very important to come up with a solid organizational scheme. Having a clean and consistent way of storing the code will make it easy to lookup and easy to know exactly what everything is used for. In my applications, I follow two main tenets:
  • Application specific plugins should be noted. I always name jQuery plugins that are specific to my product as jquery-productname-plugin-name.js. That has been working out pretty well to clearly identify them against the plugins you downloaded.
  • Javascript file names should match the controller action they correspond to and be nested in a folder matching the controller name. So your /products/new action's javascript would be in /public/javascripts/products/new.js.
I also arrange my css the same way. Doing that makes it really easy to know what is being used and where. When you blast a controller, you can safely blast the javascript and css directories matching it if you strictly followed the pattern.

Be Smart About Includes

Another thing I do is always have 2 javascript and 2 css files per page. One is the global template group and the other is the page specific group. In my application template I have this: [ruby]<%= javascript_include_tag "global.js", "jquery-tablesorter-min.js", ..., :cache => true %> <%= yield :tail %>[/ruby] Similarly, I have the same tags for my css but with yield :head instead. Then in my view, I do [ruby]<%- content_for :tail do -%> <%= javascript_include_tag "controller/action.js" %> <%- end -%>[/ruby]

Namespace!

There are three different types of javascript that will be attached to your page: in the document ready, as a plugin, or as static namespaced functions. The code in your document ready is fine. It should be pretty lean, but if there are lots of unique event handlers or whatnot, it can get pretty big. Your custom plugins should always have cool and unique names. So what do you do with the rest of the javascript? Namespace it as static functions. I don't typically write a lot of this, but sometimes it makes sense to separate code into some logical parts. Mine would look something like this: [js]var ControllerAction = { someFunction: function() { ... } }[/js] Sticking with the controller and action naming will always let you know where the functions you are calling came from. If something happens down the road and it gets included in Controller2's Action2, I can look at the function calls and know exactly where ControllerAction.someFunction() came from. Obviously, it isn't part of the Controller2Action2 namespace, so I need to look in /public/javascripts/controller/action.js to find it. So that is the organization of my Rails application javascript in a nutshell. Trying to stay as close to the Rails naming conventions as possible has helped me to keep a handle on the huge amounts of javascript I have written. Always remember, consistency is key to maintainability.

Performance Evaluation: Remember the Milk

If you aren't familiar with Remember the Milk, it is a totally awesome web-based to-do list manager. I use it religiously and recommend it to all my friends. The site is beautifully designed and very heavy with javascript. It uses ajax for everything and their server is extremely fast. It is very well implemented and they did almost everything right with their implementation. Going down the list of major things they did right...
  1. Gzipping the resources: They enabled gzipping. That is probably the easiest thing to do with the biggest bang for the buck. If you are using apache, which you probably are, then it is a very simple configuration change to enable mod_deflate.
  2. Minify the javascript: They compile their site's javascript files into a single file called rtm.{version}.js and minify it. That is a great practice and I highly recommend it. Adding the version number into the name is an excellent practice as well. That is critical to using far-future expires headers.
  3. Far-future expires headers: They added them to all the site's javascript, which makes up a significant portion of the total download. Doesn't help the first page load, but all subsequent access are all cached. Awesome.
Although there are a few other minor things that could be improved, the biggest performance issue with their site is the large number of image downloads. They could combine about 40 icons into a single (or maybe 2) jpg or crushed png and use css sprites to display the various icons. On my internet connection, a refresh of the page takes almost 4 seconds to download the images and that would likely be reduced to about 1/10th of the time by using a single image. Overall, they are an excellent example of how to implement a highly interactive UI in a very efficient manner. They clearly took some care in crafting it and it pays off in the load time of the page. It is a great effort and I wish more sites on the net would do the same. If you have a site that you would like me to have a look at and post my analysis and recommendations for, please leave a comment or drop a line to paul at codingfrontier.com.

I <3 rspactor

Last night at the RubyJax meeting I was pair programming with one of the fine folks at Hashrocket and he turned me on to rspactor. It is a gem that automatically and continuously runs your rspec tests and alerts you to failures as you code. It is very lightweight easy to use. All you do is execute rspactor from your project root and off it goes. It runs your whole suite of tests to get started and then any tests that are impacted by the work you are doing as you go. There are a few other tools similar to this one. If you aren't already using one, I would highly recommend checking this out. http://rubyphunk.com/2008/3/11/hello-world-introducing-rspactor

Textmate javascript-tools == Awesome

Seriously. If you are coding javascript in Textmate and not using this, you are really missing out. It is a fantastic plugin for Textmate that allows you to very easily run JSLint on your code and compress it with your pick of compressors. Every time you save a javascript file, it will validate it automatically and let you know right away if there are any problems. It will keep you from having the trailing comma issue hit you in IE. This plugin needs to be manually installed, which is easy to do if you have never done it before. All you need to do is clone the git repository into your Bundle directory. cd ~/Library/Application Support/TextMate/Bundles git clone git://github.com/subtleGradient/javascript-tools.tmbundle.git If you want to update the plugin after that, just do a git pull and you are all set. Here is the project link if you want to follow them on GitHub. http://github.com/subtleGradient/javascript-tools.tmbundle/tree/master

One of My Favorite Functions: closest

Sometimes we may have a generic function that could be triggered from a couple of different places. For example, let's say you have an unordered list with sortable li tags inside and clickable anchor tags that fire the same event to do whatever with the acted on list element. New with jQuery 1.3 is the closest function, which will find the closest element matching the selector, including self. That means that in the scenario defined above we can have a function that looks like this to handle the event. [js]function() { var element = $(this).closest("li"); ... }[/js] Pretty clean code and it will work as long as the event is triggered anywhere from the target li all the way down through any of its children. This function is very similar the the parents function that we all know and love. That, of course, will not include the starting element in the search though.

When to Extend jQuery

More often than you might think. I have found that writing jQuery extensions is a clean and readable way to write not only plugins, but also application and page specific code. Recently there have been two scenarios where I found it appropriate to write some extensions. The first is when you are using a plugin in multiple places and have a common way of invoking and interacting with it in your application. I was working with a modal window that was popped from multiple places, so I wrapped the modal plugin in my own extension that knew all the default settings and behaviors for the modal. That way my pages that used it could just invoke my plugin and not have to duplicate all the setup code. This is just an example to illustrate the technique, so please don't bother trying to execute it. [js](function($) { $.fn.extend({ openMyModal: function(options) { //Merge the passed in and default settings, then call the plugin code. this.popmodal($.extend($.logWorkoutResults.settings, options)); } }); $.extend({logWorkoutResults: { settings: { someSetting: 'blah', success: function() { ... } } }); })(jQuery);[/js] So the gist of what we're doing here is providing the common set of settings and function overrides in one place, but still allowing them to be overridden by the caller. The default settings and the passed in settings will be merged and then the plugin will be invoked. You would call it like this: [js]$(".selector").openMyModal({ someSetting: 'blah blah' });[/js] Pretty clean and easy to use, yet still easy to override if a certain page needs to change things. You can really go crazy with this, too. Since it is your extension just using a plugin, you can add all sorts of additional functionality. The other time that it makes a lot of sense to write your own is when you find yourself writing loose functions that take one or more DOM elements as a parameter, or even if your function selects some elements and acts on them. For example, let's look at this plain old function call. [js]MyPage.myFunction($("div.somestuff"), { parm1: 'value' });[/js] Instead of having a loose function that depends on being passed a jQuery element, just rewrite your function to extend jQuery and it gets a whole lot cleaner. [js]$("div.somestuff").myFunction({parm1: 'value'});[/js]The inside of the function is easy to change, too. The old one would have looked like this: [js]var MyPage = { myFunction: function(elements, settings) { elements.each(function() { //do stuff with 'this' }); } };[/js] But now it will just look like this: [js](function($) { $.fn.extend({ myFunction: function(options) { this.each(function() { //do something with 'this' }); } }); })(jQuery);[/js] So the implementation code doesn't look that much different, but the calling is a whole lot cleaner and easier to follow. You can just include that extension at the top of your page's js file or where it makes sense.

Live Event Handlers

If you are modifying the DOM on the fly, then you have probably noticed that any event handlers you attach don't work on elements added after page load. Let's say you are making an ajax request and your server is returning an html response that you replace a portion of your DOM with. All the normal event handlers that were applied at page load were not applied to these elements, since they didn't exist at that time, and so now you have a bunch of stuff on the screen that doesn't work. Your first thought might be to re-add all the event handlers after the DOM update is complete. This would get the job done, but wouldn't be very efficient and would require the event attachment code to be in multiple places. A better approach would be to use the "live" function introduced in jQuery 1.3 (or the livequery plugin if you are still on 1.2). Instead of applying directly to the element, it captures bubbled events and checks the target element to see if it matches what is being watched. That way, an event on any element that matches the live's selector will have the event fired. The call is basically the same, except you pass in the name type of event to watch for. [js]$("a.link_to_watch").live('click', function() {});[/js]At the time of writing this post, the event types not supported are blur, focus, mouseover, mouseleave, change, and submit. If you need to attach to those types of events, you will need to use the livequery plugin instead.