jlaine.net

From Rails Ajax Helpers to Low Pro, Part I

1728 words · 9 min read

[]{lang=”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:

<code class="html"><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;">
</code>

Even link_to_remote and link_to_function give you the option to specify the href attribute manually and thus make the link accessible:

<code class="ruby"><%= link_to_function "Add new item",
    "$('add_form').toggle()", :href => "/foo" %>
</code>

➥

<code class="html"><a href="/foo"
   onclick="$('add_form').toggle(); return false;">
  Add new item
</a>
</code>

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:

<code class="ruby"><%= link_to_function "Add new item",
    "$('add_form').toggle()" %>
</code>

➥

<code class="html"><a href="#" onclick="$('add_form').toggle(); return false;">
  Add new item
</a>
</code>

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:

<code class="html"><a href="/foo"
   onclick="$('add_form').toggle(); return false;">
  Add new item
</a>
</code>

Using Low Pro, this could easily be made unobtrusive:

HTML file

<code class="html"><a href="/foo" id="add_item_link">
  Add new item
</a>
</code>

Javascript file

<code class="javascript">Event.addBehavior({
  '#add_new_link:click' : function() {
    $('add_form').toggle();
    return false;
  }
});
</code>

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_behaviour that 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 and assert_select Rails test assertion) to select to which elements certain behaviours should be attached.
<code class="ruby"><% apply_behaviour "#add_item_link:click", "alert('Foo clicked!')" %>

<% apply_behaviour "#another_link:click" do |page|
    page.alert "Ah, you clicked me again"
  end %>
</code>
  • It added a couple of helpers to be used with apply_behaviour to call the most common prototype and script.aculo.us effects:
<code class="ruby"><% apply_behaviour "#sort_list", make_sortable %>

<% apply_behaviour ".ajax_link", make_remote_link %>
</code>

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:

<code class="javascript">Event.addBehavior({
  'a.todo:click' : Link.Remote,
  'div.feature:mouseover' : function(e) {
    this.hide();
  }
});
</code>

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”:http://domscripting.com/presentations/xtech2006/” 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!

Dubbing of the Simpsons Movie

111 words · 1 min read

Guan brings up an interesting point about The Simpsons Movie. Just like in Denmark, it’s distributed here both as original and a dubbed Finnish version. It’s been common to dub films here that are clearly targeted at small children. However, dubbing Simpsons is interesting for two reasons:

  1. Just like in Denmark, Simpsons the series has never been dubbed in the Finnish TV. People, even the children, are used to the certain American voices the characters have.
  2. From what I’ve heard (I’ve yet to see the film) Simpsons the Movie is not really a children’s movie at all, just like the series has never been aimed at children that can’t yet read.

A Tale of a Cheque

468 words · 3 min read

One thing that never stops amazing me is the eagern€US companies to use cheques as a pa€ethod. I mean, we have been using online banks for more than a decade now, and still the default way of paying a contractor is sending him a cheque.

Sure, the buyer wins some time (and thus a few days’ worth of interest€or the receiver of the payment it goes like this:

  1. Wait for the cheque to arrive in mail. This normally takes about a week.
  2. Walk to a bank and get stared at like a lunatic, because you’re considered a remnant from the era of ball chairs. Stand in line for half an hour because banks have cut their counter workers to a minimum (since no one - except for pensioners - goes to a bank persionally these days, and pensioners have time to wait).
  3. Wait another week for the cheque to be cashed and the money to arrive on your account.

Now let’s compare this to the process of a bank wire:

  1. [… there is no step 1.]{.laughter} You just wait and after about a week since the customer sends the money it’s on your account.

Now as if this wasn’t enough, here’s what just happened with a cheque I received a couple of months ago. When I got the cheque, the dollar rate was near it’s all-time low (around $1.35/€1), so I decided I’d wait for a while for it to stabilize. That turned out to be just a pipe dream so I bit the bullet and walked into a bank this week. No problem.

Today I got a call from the bank. They told me they have a 70-day limit in cashing cheques in the normal fashion (which costs me about €12). Since they don’t want to take the risk of being denied by the US bank that issued the cheque, the only way to cash it now is as a CAD (cash against documents) cheque, which, coincidentally, is going to cost me around €50. Just great.

For a reality check, I decided to call another bank and ask how it would work there. The person with whom I talked obviously wasn’t prepared to answer such a hard question as “How much does cashing a cheque cost?”, so I had to wait on hold for a while until she came back with the answer. And what an answer that was:

“The bank has the option to deny cashing the cheque as its will, and the cost is always at least €90.” Geez. I called back to the original bank and told them to go ahead with the cashing. It seems the banks in Finland have at least as bad an aversion to cheques as I do.

From no on, please don’t offer to pay me by a chequ

Advanced Concepts in Ruby on Rails Hosting

79 words · 1 min read

I’ve recently been looking into Starfish to provide more speed for our upcoming email alert functionality. While reading Lucas’ blog I noticed that he’s back blogging about their experiences at MOG. This time he’s writing a series about Rails deployment which seems really interesting. Three parts so far, more to come:

RailsConf Slides

52 words · 1 min read

Here’s the PDF export of my RailsConf slides. Unfortunately they probably don’t make much sense just by themselves. I’ll try to post the transcript of the talk as well, as soon as I get back on the normal track of life after three weeks of travelling.

Angel on the Shoulder (PDF, 4,5MB)

Going to Tiomila

546 words · 3 min read

‘tis the time of the year again. The week when you can hardly concentrate on your work, school or household. In a few hours we’ll jump in a ship towards Sweden and then drive to Eskilstuna and Gröndal speedway stadium which hosts this year’s Tiomila.

It’s hard to describe to a non-orienteer the feelings one has before an event like Tiomila (and even more, Jukola). It’s for many the event where the countless hours and kilometers spent running and xc skiing through the woods materialize, where the whole orienteering world gathers in one place to see which club has most successfully trained through the winter, avoided injuries and illnesses, and generally prepared for the major races of the year.

Let me in this entry stay in Tiomila. Late April, possibly sun, probably rain and cold. Lots of mud, sometimes even a hint of snow. Ten men in a team, all with a common goal of surviving through the night and the 111 km (of which more than 60 in darkness) as fast as possible, in the best case faster than anyone else.

Tiomila, and especially its 4th “LÃ¥nga natten” (“Long night”) leg, spanning 16,5 km, is full of legends. Once in mid-90’s, Sören Nymalm, my former clubmate and one of the greatest night orienteers of all time, was heading a pack of a dozen runners on LÃ¥nga natten. Sören had had pizza the day before which obviously wasn’t any good for his stomach. In the middle of the leg, Sören had to jump off a dirt road to relieve his abdominal pains.

What a great chance to escape for the rest of the pack! But what happened? The whole group waited for Sören, and someone even spared him some toilet paper. After (and despite) the accident, Nymalm continued to lead the group and ran one of the fastest times on the leg. It paid off to stand by him.

Another legend from about two decades ago is that the leading pack of runners on LÃ¥nga natten followed the wrong path and öup on the opposite side of a lake to their next control. According to some, part of the pack then tried to steal a rowing boat to cross the laöö others humbly turned around and ran back around the bay. The truthfulness of the latter part of this stoös över at least a bit questionable. The point is, however, that an event like Tiomila is a fertile ground for legends like these.

The modern technology has brought its own twists to the relay. With the help of live GPS tracking and öting, you can now follow through the night (or afternoon if you happen to live in US) and sense at least part of the atmosphere without leaving your beloved Aeron.

If none of my babblings got you excited, here’s a brief YouTube video from last year’s TV/webcast.

``{=html}`</param>`{=html}``{=html}`</param>`{=html}``{=html}`</embed>`{=html}`

`{=html}

If you’re spending Saturday night in front of a screen, go ahead and dedicate your secondary screen for the webcast. The men’s mass start at 9PM GMT (launched by an AA cannon) is one of the most spectacular things you can experience in sports.

But now, it’s time for my last finishing up training and then some packing before our car heads to the harbor.

Sad

160 words · 1 min read

There are few authors whose writings literally change your life. For me, Kathy Sierra has been one of them. She’s been the leading teacher in how we can cross the chasm between software and emotions, vendors and clients, hackers and users, male and female hackers, the list goes on. I’ve seen Kathy talk in person and it’s hard to imagine a nicer personality.

It was thus with great shock and sadness when I read about the death threats that Kathy has been getting. It made me sick. It made me cry.

The comments made about growing a thick skin and getting used to this turned my stomach even worse. This is not about trolling, this is about threatening to kill and sexually harass someone. There is just no excuse in the world for that.

I hope we can now show the power of the community to fight the abusers and show there’s no place for such behaviour in the blogosphere.

Making Cached_model and Observers Like Each Other in Rails 1.2

409 words · 3 min read

I recently updated my RubyGems to 0.9.2. In that upgrade, require_gem was deprecated in favor of gem and running Rails would generate a bunch of deprecation warnings. However, it was easy enough to fix by running rake rails:update in the app root.

Doing the update caused us some problems, though, because we are using the cached_model gem to store objects in memcached. cached_model was required in environment.rb before the Rails::Initializer.run block but with the new autoloading mechanism, it didn’t work anymore because the Rails classes weren’t at the disposal of cached_model before the initializer block. Instead I got all these weird errors:

$ script/console
Loading development environment.
/opt/local/lib/ruby/gems/1.8/gems/cached_model-1.3.1/lib/cached_model.rb:21:NameError: uninitialized constant ActiveRecord
/opt/local/lib/ruby/gems/1.8/gems/actionpack-1.13.3/lib/action_controller/assertions/selector_assertions.rb:525:NoMethodError: undefined method `camelize' for "top":String
./script/../config/../config/../app/controllers/application.rb:1:NameError: uninitialized constant ActionController::Base

Lo and behold, the cached_model docs instruct to put the require line after the initializer block. This is the right way and should be ok in most cases. However, in our app, we also have an observer for the User class, which is a subclass of CachedModel. Observers are loaded inside the initializer block (config.active_record.observers = :user_observer) and when loaded, they also initialize the actual ActiveRecord model they’re observing (in this case User). But since User subclasses CachedModel, which is not loaded yet, we have a chicken and egg problem:

$ rake test:units
rake aborted!
uninitialized constant CachedModel

We can’t require cached_model before the initializer because ActiveRecord::Base doesn’t exist then, and we can’t require it after the initializer because it would need to be initialized when the observers are loaded. What’s a man to do?

Rick Olson pointed me to a list of articles (1, 2, 3) that he recently wrote about the Rails initializing mechanism (+ a link to another useful article by Tim Lucas). This lead to a trick that solved my problem. Namely, writing a plugin.

The gist of the trick is that the loading of observers is deferred until all plugins are loaded. So I created an empty plugin called cached_model_plugin, put the require 'cached_model' line in its init.rb, and everything started working again. Woo-hoo!

The weird thing about this is that actually, the code in environment.rb after the Rails::Initializer.run block should also be run before the observers are loaded. However, for whatever reason that didn’t happen in our case, so I’m happy that using a dummy plugin helped.

With the new config/initializers in Rails Edge this hack should become history, but until we update beyond 1.2.X, we’ll be camping happily with my plugin.