Rails-JavaScript Named Routes (Re)Visited

Almost a year ago I was unable to find a plugin that did something that I considered rather basic—allow for easy URL generation from JavaScript based on routes defined in Rails. I hacked up a proof of concept albeit rough solution and posted it to this blog. Delightfully, Joshua Sierles ran with the idea, improved upon it, and published a plugin.

A year later and thanks in part to the ease of collaboration provided by GitHub, I've formally paid my respects to Joshua's plugin by updating it for Rails 2.1, adding support for caching the generated javascript file, and a couple small features to make the javascript helpers behave a little more like the "real" Rails named route helpers.

What it does

Suppose that you had the following RESTful route defined in routes.rb:

map.resources :posts

Then, you'd get these (and other) familiar-looking javascript URL helpers:

posts_url() => "http://localhost:3000/posts"
post_url({id: 3}) => 'http://localhost:3000/posts/3'
post_path({id: 3}) => '/posts/3'
formatted_post_path({id: 3, :format, 'xml'}) => '/posts/3.xml'

The javascript generated by this plugin does not depend on any third-party javascript library.

Install

Assuming you are using Rails 2.1 RC1 or later, you can use the Rails script/plugin install command:

$ cd RAILS_ROOT
$ script/plugin install git://github.com/jsierles/js_named_routes.git

This plugin is targeted at Rails 2.1 and may not be compatible with other Rails versions without minor modifications.

Usage

At startup, a route for the plugin's all-important javascript generating NamedRoutesController is dynamically injected. With the plugin installed, visit the following URL to inspect the provided javascript helpers:

http://localhost:3000/javascripts/named_routes.js

Then, include the above javascript URL in your HTML head tag (probably in application.html.erb or some other layout file):

<%= javascript_include_tag :named_routes %>

And you're done. Go have some fun!

// Mootools 1.2b
new Request({url: post_comments_path({post_id: 4}) }).post({
  post_id: 4, comment: {body: "something useful"}
});

// jQuery
$.post(post_comments_path({post_id: 4}), {
  post_id: 4, comment: {body: "something useful"}
});

// Prototype
new Ajax.Request(post_comments_path({post_id: 4}), {
  method: 'post',
  parameters: {post_id: 4, comment: {body: "something useful"} }
});

Just like in Rails, specified route segments that aren't part of the route will be added as query parameters:

post_url({id: 3, extra: 'galen'}) => 'http://localhost:3000/posts/3?extra=galen'
post_path({id: 3, extra: 'galen'}) => '/posts/3?extra=galen'

This plugin uses page caching to cache the generated javascript routes, but lacks any intelligence for sweeping the cached file if you've made changes to your routes. That shouldn't be a problem if you are using Capistrano for production deployments because the cache is normally stored in RAILS_ROOT/public which is not kept across deployments. Caching is normally disabled in development mode, but if you turn on caching you may need to manually clear the cached file:

$ cd RAILS_ROOT
$ rm public/javascripts/named_routes.js

Alternatives

I'm pleased that there are at least two other plugins that also aim to satisfy the need to dynamically generate URLs based on Rails named routes: LessJsRoutes and JavaScript Routes.

LessJsRoutes offers similar syntax to js_named_routes. A notable difference is that the javascript routes file is built via a rake task and therefore needs to be manually re-built whenever you make a change to your routes. LessJsRoutes also depends on either jQuery or Prototype, but perhaps only if you take advantage of their handy looking _ajax helper methods (I haven't checked into this). They also support a more compact but still Rails-like syntax for specifying routes: post_url(3) rather than post_url({id: 3}).

JavaScript Routes (not to be confused with js_named_routes) has a very different and more verbose syntax. While I personally prefer simpler and more Rails-like syntax, the plugin appears to be able to generate routes other than "named routes." Like LessJsRoutes, it also relies on a rake task to manually build the javascript routes file.

Sorry, comments are closed for this article.