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

We're looking for senior developer. More Info

Posted by
Geoff Buesing

Posted on
17 May 2007 @ 11pm

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

JQuery Ajax + Rails

UPDATE
Old stuff here! See Errtheblog’s post on jQuery for more up-to-date information…

***

I’ve been working on integrating jQuery’s Ajax capabilities into a Ruby on Rails application; here’s what I’ve discovered so far:

RJS templates (yes, you can use them!)

UPDATE see Javascript + embedded Ruby templates with Rails, out-of-the-box for a way to skip using RJS templates altogether and write .js.erb templates (Edge Rails only.)

After playing around a bit with various options (like rendering Javascript from a standard .rhtml partial) I was surprised to discover that I could use RJS templates to write jQuery-specific Javascript.

Given that the Prototype syntax for element proxies — $(id) — is the same syntax as the jQuery object — $(selector) — the RJS element proxy syntax — page['someid'] — can be used to output a jQuery object. Built-in method_missing magic handles the arbitrary methods chained to it. Examples:

page["#posts"].append render(:partial => ‘post’, :locals => {:post => @post})

#=> $("#posts").append("Post #29 info…");

page[".hide-this"].hide

#=> $(’.hide-this’).hide();

page["#foo"].html("bar").append("baz")

#=> $("#foo").html("bar").append("baz");

page["h1"].add_class "make-red"

#=> $("h1").addClass("make-red");

In addition to the element proxy, the following JavaScriptGenerator methods can be used as well, since they output non-Prototype specific Javascript:

page.delay(5) do

page.alert ‘hello from rjs’

end

page.call ‘myfunction’

page << "arbitrary js code"

page.assign ‘foo’, ‘bar’

Any commands that can’t be written with the page['selector'].method syntax can always be added to the page as raw Javascript with page << “javascript”.

Unobtrusive Ajax links

I have no need for a jQuery version of the link_to_remote helper — I just use the standard link_to and assign behavior to it unobtrusively via jQuery’s $(document).ready() function. Here’s how I build a jQuery Ajax link that will retrieve and evaluate Javascript from a RESTful Rails controller method with a respond_to block:

<%= link_to ’show post’, post_path(post), :class => ‘do-stuff’ %>
<script type="text/javascript"><!–mce:0–></script>

Since the default HTTP Accept header for jQuery Ajax requests is “text/xml”, I need to change it to “text/javascript” with the setRequestHeader method so that the request triggers the appropriate response format (format.js) in the controller method’s respond_to block. Alternately, I could set the link href to formatted_post_path(post, :js), but that of course wouldn’t degrade as well.

If I want to simply return an HTML partial and insert it into the DOM, I can change the Ajax object so that it expects HTML, and add a success handler function to process the returned HTML:

<%= link_to ’show post’, post_path(post), :class => ‘post-detail’ %>
<script type="text/javascript"><!–mce:1–></script>

Just like Prototype, jQuery sets the X-Requested-With header to XMLHttpRequest for Ajax requests, so I can query request.xhr? in my controller if I need to distinguish between standard and Ajax requests. Here’s an example from a controller action where I render a partial if the request is Ajax, and the default .rhtml template for that action if it’s a standard request:

 def show

@post = Post.find(params[:id])    respond_to do |format|

format.html { render :partial => ‘post’, :locals => {:post => @post} if request.xhr? }

format.xml  { render :x ml => @post.to_xml }

format.js

end

end

Here’s how I could create a link with a DELETE method instead of GET (similar to adding the :method => :delete option to the link_to):

<%= link_to ‘Destroy’, post_path(post), :class => ‘post-destroy’ %>
<script type="text/javascript"><!–mce:2–></script>

But of course, this won’t degrade successfully; with Javascript turned off, this link will just GET the show method. For a degradable, form-based solution, I can use…

Unobtrusive Ajax forms

For Ajax forms, I just use the JQuery Form Plugin to unobtrusively Ajaxify a standard form — no remote_form_for necessary! Example:

<% form_for :post, Post.new, :url => posts_path, :html => { :id => "new_post" } do |f| %>

<%= f.text_field :title %>

<%= f.text_area :body %>

<%= submit_tag "Create" %>

<% end %>
<script type="text/javascript"><!–mce:3–></script>

Testing

assert_select_rjs won’t work for parsing jQuery-specific Javascript (and the ARTS plugin only seems to work for certain simple cases.) Instead, I’m just using assert_match on the @response.body in my functional test:

def test_get_post_via_xhr

xhr :get, :show, :format => ‘js’, :id => 1

assert_response :success

assert_match /text/javascript/, @response.headers[‘type’]

assert_match /post title/, @response.body

end

…and all of this works out-of-the-box, no special helpers or plugins required!

Just load jQuery (and jQuery.form, if needed) in your application layout and you’re good to go.

Other stuff to check out

I’ve yet to test out Dan Webb’s MinusMOR plugin, which kind of turns rjs templates inside out — instead of writing your Javascript with Ruby, you embed Ruby in your Javascript via .ejs templates, which are served just like .rjs templates.

And there’s Yehuda Katz’s yet-to-be-released JQuery on Rails, which sounds promising.


15 Comments

Posted by
weepy
20 May 2007 @ 11am

This is great stuff !!


[...] jQuery works nicely with Rails. [...]


Posted by
Rich Manalang
21 May 2007 @ 6pm

Good stuff! I’m working on a project now that uses jQuery with Rails. I only wish that Rails can come with jQuery as an optional library by default.


[...] was really thrilled to learn that JQuery can work nicely with Rails and then went on to read criticism of using Prototype in web [...]


Posted by
links for 2007-05-22 « manalang
22 May 2007 @ 4am

[...] JQuery Ajax + Rails jQuery works with Rails out-of-the-box! (tags: rails jquery rubyonrails javascript) [...]


Posted by
Tim Rogovets
24 May 2007 @ 9am

Awesome info!
Very clever work.


Posted by
links for 2007-06-12 « /tmp
12 June 2007 @ 4pm

[...] mad.ly – JQuery Ajax + Rails (tags: javascript Ajax jquery) [...]


[...] JQuery Ajax + Rails how to integrate jQuery’s Ajax capabilities into a Ruby on Rails application; (tags: rubyonrails javascript jQuery) [...]


Posted by
Paul Irish
22 September 2007 @ 10pm

Jeremy Durham seems to have picked up the jquery+rails torch.. http://www.jeremydurham.com/


Posted by
Arik
31 October 2007 @ 2pm

Rails is very opinionated, jQuery is not coming to rails anytime soon…


Posted by
Laurens
26 November 2007 @ 3pm

Hi Geoff,

I found out that the current JQuery version (> 1.1.2) breaks the above request with

url: this.href,
and
dataType: “script”,
and
xhr.setRequestHeader(”Accept”, “text/javascript”);

this.href contains the whole url including the host part thus it seems like a remote url. With remote urls JQuery doesn’t do a XHTTPRequest but appends a tag to the DOM, which doesn’t send the manually set request headers.

Any solution for this problem?

Laurens


Posted by
Laurens
26 November 2007 @ 3pm

one obvious fix I’m using right now is removing the host part from this.href…


Posted by
Aaron
26 November 2007 @ 10pm

I just completed a plugin called jRails that makes using jQuery with Rails very easy. It is essentially a drop-in jQuery replacement for Prototype/script.aculo.us on Rails and you get all of the same default Rails helpers using the lighter jQuery library.
http://www.ennerchi.com/projects/jrails


Posted by
Rabbit
6 January 2008 @ 9am

Thank you, thank you, thank you!

I was having a frustrating issue with Rails’ new cookie-based authenticity token and respond_to.

Interestingly enough, just before I found this page I was wishing there was more documentation for jQuery’s beforeSend attribute. So this little bit:

beforeSend: function(xhr) {xhr.setRequestHeader(”Accept”, “text/javascript”);}

Was like a holy grail for me. Thanks again!


[...] Mapping Microformats with jQuery 53. A List Apart: Articles: Frameworks for Designers 54. mad.ly – JQuery Ajax + Rails 55. 1007 + Ajax/Javascript/Dhtml examples and demos to download 56. QuarkRuby: Why I moved from [...]