---
title: A Tour of Rails’ jQuery UJS
teaser:
tags: web,rails,javascript
author: Derek Prior
published_on: 2013-11-09
---

If you have a look at the default `application.js` file generated by Rails,
you’ll see `//= require jquery_ujs`. You might know exactly what this require is
for, but if you’re like me you know you need it but have only a vague idea of
what it’s responsible for.

Maybe you’ve looked at that line and thought, “I should really figure out what
that does someday.” Well, for me, today is that day. I thought you might want to
join me.

## Unobtrusive JavaScript

The UJS in `jquery-ujs` stands for [unobtrusive JavaScript][ujs]. This is a
rather broad term that generally refers to using JavaScript to progressively
enhance the user experience for capable browsers without negatively impacting
clients that do not support or do not enable JavaScript.

`jquery-ujs` wires event handlers to eligible DOM elements to provide enhanced
functionality. In most cases, the eligible DOM elements are identified by [HTML5
data attributes][data].

Let's have a look at the progressive enhancements `jquery-ujs` provides.

[data]: http://ejohn.org/blog/html-5-data-attributes/
[ujs]: http://en.wikipedia.org/wiki/Unobtrusive_JavaScript

## POST, PUT, DELETE Links

    <%= link_to 'Delete', item, method: :delete %>

Clicking a link will always result in an HTTP `GET` request. If your link
represents an action on a resource it may be more semantically correct for it
to be performed with a different HTTP verb; in the case above, we want to use
`DELETE`.

`jquery-ujs` attaches a handler to links with the `data-method` attribute. When the link is clicked, the handler constructs an <abbr title="HyperText Markup Language">HTML</abbr> form along with a hidden input that sets the `_method` parameter to the requested HTTP verb and submits the form rather than following the link.

## Confirmation Dialogs

    <%= form_for item, data: { confirm: 'Are you sure?' } %>

`jquery-ujs` attaches a handler to links or forms with the `data-confirm`
attribute that displays a JavaScript confirmation dialog. The user can choose
to proceed with or cancel the action.

## Disabling Links and Buttons

    <%= form.submit data: { disable_with: 'Submitting...' } %>

Users double click links and buttons all the time. This causes duplicate
requests but is easily avoided thanks to `jquery-ujs`. Links and buttons that
have a `data-disable-with` attribute get a click handler that disables the
element and updates the text of the button to that which was provided in the
data attribute and disables the button. If the action is performed via AJAX,
the handler will re-enable the button and reset the text when the request
completes.

## AJAX Forms

    <%= form_for item, remote: true %>

Adding `remote: true` to your `form_for` calls in Rails causes `jquery-ujs` to
handle the form submission as an AJAX request. Your controller can handle the
AJAX request and return JavaScript to be executed in the response. Thanks to
`jquery-ujs` and Rails’ `respond_with`, setting `remote: true` is likely the
quickest way to get your Rails application making AJAX requests. The unobtrusive
nature of the implementation makes it simple to support both AJAX and standard
requests at the same time.

## AJAX File Uploads

Browsers do not natively support AJAX file uploads. If you have an AJAX form
that contains a populated file input, `jquery-ujs` will fire the
`ajax:aborted:file` event. If this event is not stopped by an event handler, the
AJAX submission will be aborted and the form will submit as a normal form.

[Remoteipart][remoteipart] is one Rails gem that hooks into this event to enable
AJAX file uploads.

[remoteipart]: http://rubygems.org/gems/remotipart

## Required Field Validation

HTML5 added the ability to [mark an input as required][required]. Browsers with
full support for this feature will stop form submission and add browser-specific
styling to the inputs that are required but not yet provided. `jquery-ujs` adds
a [polyfill][polyfill] that brings this behavior, minus the styling, to all
JavaScript-enabled browsers. There’s no default styling provided by the
polyfill, which means users of impacted browsers may be puzzled as to why the
form will not submit. There’s an [ongoing discussion][discussion] about the
appropriateness of this polyfill.

You can opt-out of this behavior by setting the “novalidate” attribute on your
form. This will cause both the `jquery-ujs` polyfill and browsers with native
support to skip HTML5 input validation. Given both the potential for confusion
in browsers without native support and the fact that browsers with native
support apply styles that may clash with your site design, handling validation
is probably better left up to each developer.

[required]: http://www.w3.org/wiki/HTML5_form_additions#required
[polyfill]: http://remysharp.com/2010/10/08/what-is-a-polyfill/
[discussion]: https://github.com/rails/jquery-ujs/issues/319

## Cross-Site Request Forgery Protection

Cross-Site Request Forgery (CSRF) is an attack wherein the attacker tricks the
user into submitting a request to an application the user is likely already
authenticated to. The user may think he’s simply signing up for an email
newsletter, but the attacker controlling that sign up form is actually turning
that into a request to post a status to some other website, using the users
preexisting session.

Rails has [built in protection][CSRF] which requires a token only available on
your actual site to accompany every `POST`, `PUT`, or `DELETE` request. In
collaboration with `<%= csrf_meta_tags %>` in your application layout `HEAD`,
`jquery-ujs` augments this protection by adding the CSRF token to a header on
outgoing AJAX requests.

`jquery-ujs` also updates the CSRF token on all non-AJAX forms on page load,
which may be out-of-date if the form was rendered from a fragment cache.

[CSRF]: http://guides.rubyonrails.org/security.html#cross-site-request-forgery-csrf

## Extensibility

`jquery-ujs` exposes its functions in the `$.rails` namespace and [fires many
events][events] when submitting AJAX forms. `jquery-ujs` behavior can be
customized by overriding these methods or handling the appropriate events. We’ve
already seen `Remoteipart` as an example of custom event handling. There also
exist several gems that override `$.rails.allowAction` to replace JavaScript
confirmation dialogs with application-specific modal dialogs.

[events]: https://github.com/rails/jquery-ujs/wiki/ajax
