DRY Up Your AJAX Code With the jQuery.rest Plugin

Posted by Adam Lassek | August 03, 2010

We’ve been writing a lot of AJAX code with jQuery talking to our Rails backend, and lately we’ve been noticing a lot of duplication happening. There are several things that you need to do for Rails all the time that add up to a lot of tedium. Here’s a small jQuery plugin we developed to make this easier and DRY up our code.

jQuery.rest project at Github

This is basically just a simple wrapper around the jQuery.ajax function which does the tedious stuff for you. It also allows a regular parameter format with optional parameters, although you can use the standard jQuery.ajax options object if you like.

This was originally inspired by Nathan Bubna’s JSON-REST plugin. While that plugin was a good start, it just wasn’t quite as seamless as we wanted.

Here’s how it works. jQuery.rest adds four public methods: $.create, $.read, $.update and $.destroy.

Each of these four methods accepts 1-4 parameters:

URL [, data ] [, success ] [, error ]

URL: The url of the resource, which can include a dynamically populated value surrounded by {braces}

data: (optional) The data to post to the resource, also used to populate dynamic values. In GET requests, data will be added to the url as query-string parameters

success: (optional) The success callback

error: (optional) The error callback

Before you start

Two things you need to configure before using this. First, set up your controller to respond to the AJAX calls correctly:

app/controllers/application_controller.rb

1
2
3
4
5
6
7
8
9
10
11
before_filter :correct_safari_and_ie_accept_headers
after_filter :set_xhr_flash

def set_xhr_flash
  flash.discard if request.xhr?
end

def correct_safari_and_ie_accept_headers
  ajax_request_types = ['text/javascript', 'application/json', 'text/xml']
  request.accepts.sort! { |x, y| ajax_request_types.include?(y.to_s) ? 1 : -1 } if request.xhr?
end

public/javascripts/application.js

1
2
3
4
5
$.ajaxSetup({
  beforeSend: function(xhr) {
    xhr.setRequestHeader("Accept", "text/javascript");
  }
});

This will make sure Rails is treating your AJAX requests correctly in the controllers.

app/views/layouts/application.html.erb

1
<%= javascript_tag "var AUTH_TOKEN = #{form_authenticity_token.inspect};" if protect_against_forgery? %>

This stores the authenticity_token into a javascript variable so jQuery.rest can access it.

Wiring up the AJAX requests in your controller

Now let’s wireup our hypothetical tasks_controller:

app/controllers/tasks_controller.rb

1
2
3
4
5
6
def show
  @task = Task.find(params[:id])
  respond_to do |format|
    format.js { render :json => @task.to_json }
  end
end

Using jQuery.rest

Here’s how to use the tasks#show action with jQuery.rest:

1
2
3
4
5
6
7
$.read(
  '/tasks/54',
  function (response) {
    // do something with task here
  }
);
// => [GET] /tasks/54

Let’s say you want to the update the task:

1
2
3
4
5
6
7
8
9
$.update(
  '/tasks/54',
  { description: 'lunch meeting at 1pm' },
  function (reponse) { alert('successfully updated task.'); }
);
// => [POST] /tasks/54
// => authenticity_token: K06+3rRMlMuSoG60+Uw6UIo6UsZBbtIIPu2GaMbjf9s=
// => _method: update
// => description: lunch meeting at 1pm

Or want to create a new one. Callbacks are optional if you don’t need them.

1
2
3
4
5
6
7
$.create(
  '/tasks',
  { description: 'follow up after meeting' }
);
// => [POST] /tasks
// => authenticity_token: K06+3rRMlMuSoG60+Uw6UIo6UsZBbtIIPu2GaMbjf9s=
// => description: follow up after meeting

Let’s say tasks are nested under the account model. String concatenation is annoying.

1
2
3
4
5
6
7
8
$.update(
  '/accounts/{account_id}/tasks/{id}',
  { account_id: 3386, id: 54, description: 'lunch meeting no later than 11am.' }
);
// => [POST] /accounts/3386/tasks/54
// => _method: update
// => authenticity_token: K06+3rRMlMuSoG60+Uw6UIo6UsZBbtIIPu2GaMbjf9s=
// => description: lunch meeting no later than 11am.

Non-interpolated data will be added as query-string parameters in GET requests

1
2
3
4
5
6
$.read(
  '/tasks',
  { region: 5 },
  function (response) { // do something here }
);
// => [GET] /tasks?region=5

If you need to get fancy, the jQuery.ajax options object still works.

1
2
3
4
5
6
7
8
$.destroy({
  url: '/tasks/54',
  beforeSend: function(xhr) {
    // do something unusual
  }
});
// => [POST] /tasks/54
// => _method: delete

As you can see, jQuery.rest was never intended to be a big deal. It just makes writing AJAX code for Rails a lot simpler for 90% of the cases. If you think we could be making this even easier, let us know. Or better yet: fork jQuery.rest on Github and show us! Patches are welcome.

Update: you can watch my presentation for the Omaha jQuery Meetup and check out this example application for more info.

6 Comments

Nice work, looks good and I will be giving it a try, I think more people will consider using the plugin if you created a demo application and made it freely available on GitHub.

Adam Lassek

about 3 years ago
Good suggestion! I've actually done this for the local jQuery Meetup group. I'll add some links to the article & project page.

Declan McGrath

about 3 years ago
Brilliant! Thanks a mill! You rock!
I'm unable to pass null as a value for an object without null being put into quotes. Do you have any suggestions on working around this? This has been great to use other than this issue. Thanks!
@Aaron did u find a way to fix this?

maxirby

over 1 year ago
Great plugin, but for your video (presentation), I don't know what is worse sound or picture.