mad.ly rails, jquery, flash, etc    about »

We're looking for senior developer. More Info

Posted by
Geoff Buesing

Posted on
21 May 2007 @ 11pm

Tagged
ajax, javascript, jquery, rails, rjs, ruby

Integrating jQuery and Rails: use unobtrusive Javascript instead of view helpers

The jQuery Way to apply behavior to a document is to add it unobtrusively via the $(document).ready() function, ideally in an external script file… unlike the Rails Way, which is to add behavior to individual elements via inline Javascript, using the built-in view helpers.

The markup generated by these helpers is obtrusive, and often repetitive. For example, using the built-in link_to_remote helper like this:

<% for post in @posts -%>
<%= link_to_remote post.title, :url => post_path(post) %>
<% end -%>
 

…generates this HTML:

<a onclick="new Ajax.Request(‘/posts/1′, {asynchronous:true, evalScripts:true}); return false;" href="#">Post 1</a>
<a onclick="new Ajax.Request(‘/posts/2′, {asynchronous:true, evalScripts:true}); return false;" href="#">Post 2</a>
<a onclick="new Ajax.Request(‘/posts/3′, {asynchronous:true, evalScripts:true}); return false;" href="#">Post 3</a>

… which is obtrusive, non-degradable and non-DRY. Of course, one can code in an unobtrusive, degradable, DRY way with Prototype; that’s not the issue. But in looking for ways to integrate jQuery with Rails, we shouldn’t be attempting to clone all of the Rails Prototype helpers (which enable less-than-ideal coding practices) for jQuery.

Instead, we should be writing degradable HTML in our views, and adding behavior unobtrusively via Javascript.

For example, I added the following functions for Ajaxifying standard links and forms to my application.js:

// helper functions for Ajaxifying standard links and forms, and evaluating returned Javascript
$(function() {
  $("a.rjs").click( function() {
    $.ajax({
        url: this.href,
        dataType: "script",
        beforeSend: function(xhr) {xhr.setRequestHeader("Accept", "text/javascript");}
    });
    return false;
  });
  // requires jQuery.form plugin
  $("form.rjs").ajaxForm({
    dataType: ’script’,
    beforeSend: function(xhr) {xhr.setRequestHeader("Accept", "text/javascript");},
    resetForm: true
  });
});

(See my previous post about jQuery Ajax + Rails for information about how jQuery and RJS can work together.)

And now in my views, I can just add a class of “rjs” to any link or form that I want to Ajaxify:

<h2>Listing Posts</h2>
<% for post in @posts -%>

<%= link_to post.title, post_path(post), :class => ‘rjs’ %>

<% end -%>
<h3>Add a Post</h3>
<% form_for :post, Post.new, :url => posts_path, :html => { :class => "rjs" } do |f| -%>
  <%= f.text_field :title %>
  <%= f.text_area :body %>
  <%= submit_tag "Create" %>
<% end -%>

… and it works: unobtrusive, degradable and DRY.


6 Comments

Posted by
rofovnifo
4 July 2007 @ 9pm

Hi

Looks good! Very useful, good stuff. Good resources here. Thanks much!

G’night


Posted by
Sam Nardoni
17 July 2007 @ 11pm

Finally, jQuery on Rails. Oh yeah, just to let you know, i mentioned you and linked to this article in one of my posts ;)


Posted by
rrichards
29 August 2007 @ 8am

awesome information. I was thinking about this tonight and just happened to come across your posts.

EXCELLENT


Posted by
Sebastien
23 October 2007 @ 9pm

Hi, this is a good article, though quite difficult to understand for a rail/jquery beginner.

I have a remark: usually, class are used for layout, in combination with css.

The way you’re doing, every ajax links and forms have no choice but to share the same css style for their layout.

I’m no good at jquery nor javascript, but I’m pretty sure there is a way to be able to name the class of yours ajax links and forms
xxxx_rjs
where xxxx is a free name you can choose.

I think this would be more flexible.


Posted by
Ned Collyer
8 November 2007 @ 5am

Sebastien:

Class is used to describe a type of an element in the HTML.

You can have multiple classes on each.

Eg, it is perfectly valid to have

blah


Posted by
solnic
8 December 2007 @ 3pm

Hi,

You can add JavaScript behaviors using jQuery as well as other JavaScript libraries or even just “plain” JavaScript, it’s not a “jQuery Way”, it’s just unobtrusive approach to JavaScript.

Cheers!