« Doing AJAX-links right in Rails 2.0 | Main | Got Math? »

AJAX calls with fallback

When you have a list of - say - articles (that’s what I have here) and you want to change the order the items appear on the fly(maybe the newest ones first, or alphabetic or maybe clockwise…you name it…), then you have two possibilities:
The old way by providing a link that sends a “normal” request to the server which returns the same site again, with the difference of an alternated order of articles.
In rails this is pretty basic stuff:

<%= link_to 'Oldest ones first', :action => "index",
:sort_string => "created_at ASC" %>

The index-action in the controller then makes nothing different than before besides doing a database-query with the altered order-statement. And returns the site. Here the excerpt from the controller:

def index
if params[:sort_string]
    sort_string = params[:sort_string]
else
    sort_string = "created_at DESC" # the default sort order
end

@articles = Article.find(:all, :order => sort_string)
...

And there is the new cool, web 2.0 way: performing an AJAX call to the controller and just update the section of the page that needs to be updated. Without having to refresh the whole site. There you go:

<%= link_to_remote 'Oldest ones first', :url => { :action => "index",
:sort_string => "created_at ASC" }, :method => :get %>

This doesn’t work without two more lines of code. But that’s done with the blink of an eye.
In the index action of the controller you need to respond to the javascript format by adding this:

... # excerpt
respond_to do |format|
    format.html # index.html.erb
    format.js # index.js.rjs THIS LINE IS ADDED
    format.xml  { render :xml => @articles }
end
... # excerpt

Further you need to create a file with name index.js.rjs* in /app/views/YOURCONTROLLER/. Add the following line of code to this file:

page.replace_html :list, :partial => "list"

…where :list is the id of your div-element that contains the list of articles.
:partial => “list” calls the _list.html.erb partial (which contains that specific div).

The list must be wrapped in a div-element and the whole thing goes into _list.html.erb!!!
So just copy the code of the list you already have to the partial file and wrap everything in a div with id “list”. Then call the partial from that point where you removed it with <%= render :partial => “list” %>.

And then you’re done. When you hit the link, the list refreshes without loading the whole site again.

But wouldn’t it be nice to make this feature always work, even for browsers that have JavaScript disabled? I think so, ‘cause it guarantees that this works without relying on an enabled JavaScript setting. And that’s super-easy. Just modify the link in the view this way:

<%= link_to_remote 'Oldest ones first', {:url => { :action => "index",
:sort_string => "created_at ASC" }, :method => :get }, :href =>
url_for(:action => "index", :sort_string => "created_at ASC") %>

The only thing I had to add was two braces and the stuff following :href =>.
If JavaScript is enabled, the AJAX call will be send and otherwise it works as a “normal” call. Nice, heh?!?

But as you can see, the parameters passed are duplicates. The :url and :href hashes are quite similar. To DRY** things up, just write a small helper-method in application_helper.rb, that does this duplication for you:

def link_to_remote_with_fallback(name, options = {}, html_options = {})
    html_options[:href] = url_for(options[:url])
    link_to_remote(name, options, html_options)
end

And BOOM! The code’s DRY again:

<%= link_to_remote_with_fallback 'Oldest ones first', :url =>
{ :action => "index", :sort_string => "created_at ASC" } ,
:method => :get %>

Credits: DRYing up linktoremote for degradable URLs

*index is the name of the action in the controller. So modify this to match your action.
**DRY - Don’t repeat yourself

About

DanielHi. I'm Daniel Pietzsch and this is my innoQ-Blog. I'm a 26y old student at FH Bochum and working student at innoQ.
In this blog I mainly write about the progress concerning my diploma thesis which will be an in-house application for innoQ based on Ruby on Rails, but some other (geek) stuff might appear here, too.

daniel [dot] pietzsch [alt-L] innoq [dot] com

I recommend

Categories

Recent Comments

License

Creative Commons License This weblog is licensed under a Creative Commons License.
Powered by
Movable Type 3.31