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.
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
Jayoshi
over 2 years agoAdam Lassek
over 2 years agoDeclan McGrath
over 2 years agoAaron
almost 2 years agoBen
over 1 year agomaxirby
over 1 year ago