07 Jun, 2010

Published at 07:22AM

Tagged with ajax, code, javascript, jquery, programming, rails, and tips

This post has 4 comments

Ajax convention using jQuery and Rails

Really, I guess this convention could apply to anything, but some frameworks are limited in the ways in which they deal with an Ajax request/response. So I’ll be using Rails.

Rails already has several different great ways to deal with Ajax. Although, when you just want to update a DOM element with a chunk of HTML, it feels like overkill to create a whole template for a single line of jQuery. And yes, I know this topic is up for debate. Some say you should always stick with the convention of using templates. I used to agree, but I’m not sure I do anymore. You can decide for yourself.

Here’s the convention:

1
2
<%= link_to 'Send Request', some_url, :id => 'content', :rel => 'updater' %>
<div id="x_content"></div>

You have a link with an ID and a rel attribute of “updater” (that indicates that this link is used to update content on the page somewhere). The element to update uses the ID of the link with an “x_” prefix. The “x” indicates that the attribute is not used for styling, but has functionality tied to it (so don’t change it!)

And here’s the jQuery plugin that makes it work. It’s straightforward:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
$.fn.ajaxUpdater = function(options) {
  var options = $.extend({
    prefix: 'x'
  }, options || {})

  return this.each(function() {
    $(this).click(function(e) {
      e.preventDefault()

      var $dom_id = ['#', options.prefix, '_', $(this).attr('id')].join('')

      $.get(this.href, function(data) {
        $($dom_id).html(data)
      })
    })
  })
}

And to make use of it, standard jQuery:

1
$(function() { $('a[rel=updater]').ajaxUpdater() })

That will make the link request via Ajax and update the appropriate div with the response. Now, about the response. Like I said, in Rails there are several ways to do Ajax, most of which involve a template. But if you’re just needing to return a partial (read: chunk of HTML), is there really a need for a template? I’m not sure there is. Templates make obvious sense for visually representing content, but that’s not really what we’re doing here.

An example Rails action that would make this work:

1
2
3
4
5
6
7
8
def index
  @users = User.all

  respond_to do |format|
    format.html
    format.js { render :partial => "users", :object => @users }
  end
end

By rendering a partial directly within the action, it’s clear that there’s no template involved. And I, at least, combine 1) the fact that I’m in the format.js block with 2) the fact that I’m returning a chunk of HTML to conclude that the content is being injected into the page somewhere.

I’m experimenting with this approach in a current project to see how it feels. It does sort of break the MVC model given that there’s no template (or view), so you do lose that consistent “place to look” relating to the content display. But you can also see that this is a UJS approach, which means that there is still a template for the raw HTML view—this is only for Ajax requests.

What do you think?

Comments

Srdjan Wednesday, 10 Nov, 2010 Posted at 11:15PM

Cool technique. I’d probably use $.ajax instead of $.get as that gives me a clear place to handle potential errors and it’s just a bit more verbose. I’ve had $.get swallow errors from the server.

Ryan Thursday, 11 Nov, 2010 Posted at 08:51PM

Yeah, I know what you mean. But I’m mostly using this with Rails applications, so when I hit the template.js.erb I can simply check the errors myself:

1
2
3
4
5
<% if @obj.errors.blank? %>
  // do my JS fancy work
<% else %>
  $.error("<%= @obj.errors.full_messages.to_sentence %>");
<% end %>

I prefer to keep the view-changing code in with the templates, if I can help it.

Sam Atawy Thursday, 28 Apr, 2011 Posted at 06:15AM

Excellent, works great and simple to include.. I know because I’m totally naive in the ways of Rails. But how can this be used to render partials? I can’t pass parameters to a partial this way, or am I missing the obvious? It would be great if it could though, with a little tweak.

Ryan Thursday, 28 Apr, 2011 Posted at 11:58AM

Sam—Are you asking how you could render partials from a template.js.erb file? This approach is useful for when you want to simply render a partial from the controller (see above) without even worrying about a template. However, I do both.

If you want to go the template approach, your controller would NOT render a partial and instead would rely on the template execution. Keep in mind, though, if you take this approach, don’t use this jQuery plugin. You would only need to do $.get(this.href) when the link is clicked (with no callback).

From the template, you could then do something like this:

1
$('#dom_id').html("<%= escape_javascript(render("partial_name", :variable => @variable)) %>");

Hope that helps.

Do you have something to say about this post?
Retype the image to the right Spam Hint: Are You Human? Textile Formatting Tips

or

Ryan Heath | Site Management A Ruby on Rails production.

This site is a Formed Function. Formed Function LLC | @formedfunction | Get in Touch