From Rails Ajax helpers to Low Pro, part I
Posted by #
[UPDATE] Links to the latter parts of the series:
In a recent Ruby on Rails podcast interview, Dan Webb stated he’d rather see the Javascript and Ajax helpers removed from the Rails core. What was the reason a prominent Rails figure like Dan holds such a radical view on the helpers?
When Rails was young and only gaining popularity, its ability to help in quickly building Ajax-equipped web applications was one of the biggest selling points for the framework. In this, helpers such as link_to_remote and remote_form_tag played a big role. However, there are two problems looming with the Rails helpers. While the helpers did manage to make writing Ajax applications as easy as not to, they also made it very easy to fall into the two major culprits of Javascript development: writing inaccessible web applications and obtrusive JS code.
Accessibility
Accessibility in the scope of Javascript can be capped with a single sentence: Can users use the web page if Javascript is not working in their browser? For the longest amount of time, Javascript was considered synonymous to inaccessible web sites. It took a lot of evangelizing (including a book by Jeremy Keith) to convince people that peppering your pages with Javascript doesn’t inherently mean they’re inaccessible.
The technique to create sites that worked both with and without Javascript was originally called graceful degradation. The page would degrade gracefully to a less advanced one if Javascript wasn’t enabled in the browser. However, people weren’t happy with the success of graceful degradation in the larger web design circles. Therefore the strategy was basically reversed and the newcomer was labeled Progressive enhancement. The idea behind progressive enhancement is that you first build the basic functionality of the page that is available to all users, and only after that build more advanced features on that foundation.
Code produced by Rails Javascript helpers isn’t necessarily inaccessible. remote_form_tag sets the action of the form tag to the same url as the target of the Ajax call, so even if the browser doesn’t support Javascript, the form should work fine:
<form action="/items" id="add_form" method="post"
onsubmit="new Ajax.Request('/items', {asynchronous:true,
evalScripts:true, parameters:Form.serialize(this)});
return false;"
style="display: none;">
Even link_to_remote and link_to_function give you the option to specify the href attribute manually and thus make the link accessible:
<%= link_to_function "Add new item",
"$('add_form').toggle()", :href => "/foo" %>
➥
<a href="/foo"
onclick="$('add_form').toggle(); return false;">
Add new item
</a>
However, the problem is that by default the href attribute is set to ”#” (which leads nowhere), which provides an easy way to the developer to cut corners and leave the Javascript-disabled out in the cold:
<%= link_to_function "Add new item",
"$('add_form').toggle()" %>
➥
<a href="#" onclick="$('add_form').toggle(); return false;">
Add new item
</a>
Not surprisingly, many if not most Rails developers take the easy way out and just go with the default.
Obtrusiveness
Web evangelists have for long touted the wonders of separating the structure and presentation of web pages by using semantic HTML for structure and CSS stylesheets for styling the presentation. There is, however, a third part belonging to that separation equation, the behaviour. Behaviour is what Javascript is taking care of in web sites.
The separation of concerns is nothing new in the software world, and is fairly far even in the case of CSS. However, many still cobble their HTML views up with smaller or (more often) larger chunks of Javascript. This kind of Javascript usage is called obtrusive.
In unobtrusive Javascript, the HTML view should be left clean of Javascript. Instead, the elements are given id and class attributes that can then be used in separate Javascript files to attach behaviour to the elements. Consider the following bit of code:
<a href="/foo"
onclick="$('add_form').toggle(); return false;">
Add new item
</a>
Using Low Pro, this could easily be made unobtrusive:
HTML file
<a href="/foo" id="add_item_link">
Add new item
</a>
Javascript file
Event.addBehavior({
'#add_new_link:click' : function() {
$('add_form').toggle();
return false;
}
});
This not only makes the code cleaner and puts the behaviour code where it should be, it also makes it a lot more natural to begin by making the pure-HTML version work before starting to attach behaviours to it.
The path to enlightenment
Ever since the beginning of Ajax support in Rails, people wanted a way to make their apps more accessible (read the comments in my post Using Rails AJAX helpers to create safe state-changing links for discussion about making the href attribute default to the url given to link_to_remote) and unobtrusive.
In 2006 Dan Webb and Luke Redpath came out with the Unobtrusive Javascript for Rails plugin. The plugin did a bunch of things:
- It modified the Rails Ajax helpers so that they won’t just add inline event handlers to the HTML code but instead add a dom id to the element (if one didn’t already exist) and attach an event to the element in an external Javascript file that is created and cached on the fly.
- It added a helper called
apply_behaviourthat you could use to attach behaviour to elements by hand, using either pure Javascript or the domain-specific Ruby language familiar from the RJS templates. The helper used a CSS3 selector-like syntax (also familiar from the$$prototype method andassert_selectRails test assertion) to select to which elements certain behaviours should be attached.
<% apply_behaviour "#add_item_link:click", "alert('Foo clicked!')" %>
<% apply_behaviour "#another_link:click" do |page|
page.alert "Ah, you clicked me again"
end %>
- It added a couple of helpers to be used with
apply_behaviourto call the most common prototype and script.aculo.us effects:
<% apply_behaviour "#sort_list", make_sortable %>
<% apply_behaviour ".ajax_link", make_remote_link %>
Under the hood of the plugin was Dan’s Low Pro Javascript library, a light set of Javascript that makes it easier to produce accessible and unobtrusive Javascript using prototype and script.aculo.us. Low Pro introduced a few additions to the prototype element accessor methods (many of which have later been brought into prototype itself), a DOM builder, and, most important, event handling code that include declarative behaviours:
Event.addBehavior({
'a.todo:click' : Link.Remote,
'div.feature:mouseover' : function(e) {
this.hide();
}
});
As you can see, the first part of the elements in the array is the same kind of selector used in apply_behaviour—actually apply_behaviour builds this kind of Javascript calls from the Ruby code it receives. After the colon you specify either a function to be called upon the event or a behaviour class to be used (we will talk more about them in part 2). With addBehaviour, you “hijack” the basic functionality of the page and spice it with more advanced behaviour that wouldn’t be possible without Javascript.
While UJS was (and still is) a great step forward in making Javascript in Rails apps more unobtrusive – we still use it heavily on dotherightthing.com – it also has it problems. My biggest gripe with it is that while the produced HTML is clean of any Javascript, the apply_behaviour calls were still in the view code, polluting the RHTML views I was looking at days in days out. In June Dan posted a blog article titled The State (And Future) Of The UJS Plugin. In the article he writes that he’s lately not used the plugin at all and that he’s found it much better to just use Low Pro on its own without the Ruby scaffolding:
Essentially, the status is that, of late, I personally have not used UJS at all and have found a much better process by using Low Pro on its own without all the Ruby scaffolding of the UJS plugin. Secondarily, after talking to lots of developers at RailsConf it seems that the UJS plugin has failed to truly achieve it’s main goal which is to get Rails developers to write JavaScript using progressive enhancement. Many people seem to mainly use the plugin to get their JavaScript in to a separate file which is actually not even essential to progressive enhancement and I think this is a failing in the design of UJS itself. To achieve progressive enhancement you really need to think of JavaScript as a separate layer on top of a working HTML application but UJS lets you get away with keeping behavior in your views and hence leads many developers to think in the same way as they did before but think they are unobtrusive because they don’t see any JavaScript in their HTML – which is obviously not what we wanted to achieve. While many people can and do successfully use UJS for progressive enhancement even more seem not to – UJS has not been the ‘angel on your shoulder’ that I originally wanted it to be.
That single paragraph pretty much sums up my thoughts as well. And as many other people noted in the comments of the article that they, too, were mostly using just plain Low Pro instead of the plugin, I decided to give it a serious go as well. So for a recent project (a heavily Ajax-driven system) I just started writing everything without Javascript at first and then using Low Pro to progressively enhance the user experience with Ajax and other Javascript behaviours. Guess what – it’s worked wonderfully. I’m inclined to say I will never use a Rails Javascript or Ajax helper anymore. It was always more work to make them accessible than to just start with the barebones functionality and add the Javascript with Low Pro afterwards.
One initial fear I had was about dynamic serverside data that I could use with the UJS plugin. But that turned out not to be a problem at all. The cool thing about the Low Pro behaviours is that they have access to all the data on the page (even after updated by Ajax). That means you can use element id and class attribute values and the actual dynamic element content to your heart’s content. And if you really need to pass something special to the JS script alone, you can always set response headers that are then read by the Javascript code.
That’s it for part 1. Next week, in part 2, we’ll dissect an Ajax-driven, fairly inaccesible Rails page, and see how we can easily make it both accessible and unobtrusive with a few simple steps. Stay tuned!

Good article. I start using lowprow my self a few month ago and found it very elegant. I use in a camping wiki project and since camping has no js helper i was no tentating to use rails helper. I found Prototype and Lowpro a very powerfull couple of js lib.
I wait your next article on this subject.
Thank a lot.
Getting into Lowpro a little now myself and really starting to migrate away from rjs. Really felt like I was moving in the right direction then I read this blog post from 37Signals yesterday.
We moved nearly all of the application’s UI logic out of hand-written JavaScript files and into Ruby using RJS templates.
Nice writeup. One question though. Since you are putting all your JavaScript into its own file and not writing it in the views, are you putting all these functions into one global JS file that is included in every single page?
Do you do something with content_for and only include the JS file you need that way?
I’m not of lost on the basics here. It seems to me if I have a bunch of different controllers each with views that have their own IDs that may need javascript interaction, I dont want to through all those Event.addBehavior code pieces globally on every page in my app.
In that particular case, 37Singals is talking about RJS templates, not Javascript code in RHTML templates. RJS templates are only for Javascript, no HTML.
Michael: Like Arpan says, Low Pro and RJS are not really at odds here, RJS is just Ruby that is converted to Javascript. I think what Sam means is that they moved a lot of existing Javascript logic to be part of RJS Ajax responses.
Dr J: Yes, I use content_for a lot. I think it’s really a tradeoff where your mileage will vary. If you only have a bit of needed code, you can use fewer JS files that are then cached by the browser. However, part of the behaviours in the JS file wouldn’t then necessarily apply to all pages and there could even be clashes with element id’s and classes. And especially if you have a lot of different logic from page to page, I would consider dividing the JS up to separate files that are then called from the actions, e.g. through a
content_for "javascript"block.Nicely summed up. I see web developers shedding their fears and misconceptions about JavaScript all the time now, so it’s not going to be long until those nasty Rails JS helpers can be banished to the plugin underworld. The key to writing good, unobtrusive JS/Ajax is of course to know how JavaScript works, which surprisingly few do. I used to be one of them (and I’m still learning), but that was before I learnt how wonderful a language it really is. Douglas Crockford’s presentations are very helpful to start with.
I started using LowPro a few months ago, and also found it to be more efficient to build my apps first (without any JS code), and then add behavior to the page, like AJAXified form controls. Building it bare bones allows me to test the logic out easily, then I just decorate elements on the page with javascript event handlers that are activated when people interact with them.
One anti-pattern I’ve begun to see in Rails apps I’ve consulted on is the overuse of RJS templates. On some projects people tend to have one RJS template for each possible client/server interaction, resulting in tons of actions in their controllers and tons of templates in the view directory.
I’m just in the middle of converting one of those apps to using LowPro and Jester (a JS library that mimics ActiveResource) on the client side, and on the server side we have pretty standard RESTful controllers. So far its resulted in a very respectable reduction in complexity.
Basically, at first I write the bare bones controllers/actions, make sure they work with JS turned off, and then add behavior on top with LowPro. With Jester we send the data to the server, and interpret the response based on the state of the app on the client side. In effect my client-side code uses the same API as someone writing ruby and using ActiveResource would used to interact with the app.
Great article, it inspired me to write something similar, but related to the general use of JavaScript in rails apps. You can find it here
Regarding LowPro, I had some troubles with it, so I switched to “plain” Prototype, we should keep in mind that LowPro is not a requirement for unobtrusive JS :)
Surprisingly I found it really hard to explain why rails ajax helpers suck and developers should learn at least basics of JavaScript and Prototype to get things done more efficiently. I guess it’s because people don’t like JavaScript, and I’m wondering why.
Regards!