Rails URL Helpers in Javascript with JsRoutes

By Dhaivat Pandya

Screenshot 2015-01-15 12.39.58

When we use resource routing in Rails (paths like “/blogs/new” or “/blogs/2/edit”), we often use path variables such as new_blogs_path. But, when when working in Javascript, we have to hardcode the the paths, i.e. “/blog/new”. In this article, we’ll cover JsRoutes, an awesome gem that lets us use a similar set of URL helpers in our Javascript code.

Why do we need JsRoutes?

The idea is that you should not have to construct URLs manually in Javascript if a library can do it for you! This becomes evident as soon as you start doing nested routes. For example, consider the following routing configuration:

resources :posts do
  resources :comments

If we want the path to edit the comment with an ID of 4 that is associated with the post with an ID of 1, it gives “/posts/1/comments/4/edit”, which is a mouthful. It is much easier to use the URL helpers supplied by Rails than construct that string in our Javascript.


If you have the asset pipeline working in Rails, setting up JsRoutes is incredibly easy. Just add the following to the Gemfile:

gem "js-routes"

Then, run bundle install. In any Javascript file (often, in application.js), you can require JsRoutes by adding the following at the top of file:

//= require js-routes

If, as you follow along with this article, you find that JsRoutes is not loading in your Javascript, you might have to clear the asset pipeline cache:

rake tmp:cache:clear

Now, you should have JsRoutes ready to go. Let’s jump in and see some of the basics.

The Basics

Say we’ve added a new resource-based route in config/routes.rb:

resources :posts

Each post has a title field and a content field. In PostsController, we might have something like this:

class PostsController < ApplicationController
  def create
    @post = => params[:title],
            :content => params[:content])
    respond_to do |format| do
        #probably should render something more sensible in a
        #real application.
        format.json { render :json => "{}"}

Notice that we aren’t returning any errors that occur in saving the post as part of the response. This is a bad idea in practice, but we’ll let it slide since this example isn’t really concerned with the data returned from the server. In the Javascript, suppose that we have a nice form to create a new post and we want to submit that form with AJAX. Breaking out the jQuery:

$.post(path, {title: $("#title_field").val(), content: $("#content_field").val()}, function(response) {
    //do something w/ the response

But, how do we get the value of path? That’s where JsRoutes comes into play:

var path = Routes.posts_path({format: "json"});

If you tried to console.log the value of that variable, you’d see "/paths.json", as expected. It can be a little bit difficult to remember which JsRoutes calls correspond to which actions within the controller (although the names are nearly the same as the corresponding Rails helpers). One way to get a quick refresher is to add:


to one of your Javascript files and examine the output. Another way is with this handy table:

Controller#Action JsRoutes function call
posts#index Routes.posts_path()
posts#new Routes.new_post_path()
posts#create Routes.posts_path()
posts#show Routes.post_path(id)
posts#edit Routes.edit_post_path(id)
posts#update Routes.post_path(id)
posts#destroy Routes.post_path(id)

Notice that JsRoutes consists of function calls which means, in Javascript, that we have to have the calling parentheses (i.e. “()”), regardless of whether or not we have an “id” argument. Also note that some of the paths for different actions are the same (e.g. the paths for posts#index and posts#create). For these, the correct action is called based on the HTTP verb used (e.g. GET vs. POST).

Nested Routes

Alright, let’s take a look at how to handle nested routes with JsRoutes. Fortunately, if you’ve had experience with the Rails URL helpers, you’ll feel right at home. Let’s say we have this route configuration:

resources :posts do
  resources :comments

The URL helpers are a bit more wordy but the ideas are the same:

Controller#Action JsRoutes function call
comments#index Routes.post_comments_path(post_id)
comments#new Routes.new_post_comment_path(post_id)
comments#create Routes.post_comments_path(post_id)
comments#show Routes.post_comment_path(post_id, comment_id)
comments#edit Routes.edit_post_comment_path(post_id, comment_id)
comments#update Routes.update_post_comment_path(post_id)
comments#destroy Routes.post_path(id)

As a rule, if you’re passing an ID for a specific resource, use the singular form of that resource (e.g. “post”) and if you’re not passing an ID, use the plural form (e.g. “comments”).

The Magic of “to_param”

If you have URLs like “/post/138” in your application, SEO might be a bit difficult because, from the URL, it isn’t possible to tell any information (e.g. title or content) about the post the URL is referencing. That’s why Rails gives us to_param. We can see it in action in our Post model:

class Post < ActiveRecord::Base
  #maybe verify uniqueness of title

  def to_param
    title.gsub(/ /, '_').downcase


If we have a post with the title “JSRoutes is Awesome”, then we can now refer to this post as /posts/jsroutes_is_awesome which offers a slight improvement in SEO. JsRoutes lets you use “to_param” in order to generate paths as well. Let’s check out an example with a flat resource:

var path = Routes.post_path({to_param: "jsroutes_is_awesome"}, {format: "json"});

That produces the path /posts/jsroutes_is_awesome.json. This does mean that if you have a copy of the title of the post in the Javascript, you will have to reimplement the to_param logic in Javascript, which is unfortunate but, more or less, unavoidable.

Configuring JsRoutes

There are a number of ways to configure JsRoutes, which can be pretty useful for specific situations. You can manage the configuration through an initializer, so create a new one in config/initializers/jsroutes.rb. Here’s how the general format of the initializer works:

JsRoutes.setup do |config|
  config.option = value

Basically, you have a bunch of possible configuration options that you can set. Let’s take a look at some of them. One of the most useful for me has been:

JsRoutes.setup do |config|
  config.default_url_options = {:format => "json"}

That takes all of the url helpers and by default, tacks on a “.json” at the end. If you’re writing a one-page application where most of your HTTP requests are actually fired by Javascript, you almost never load HTML, as most of your data will be in JSON. In that case, it makes more sense to set the default format to be JSON.

Another important URL configuration option is :exclude:

JsRoutes.setup do |config|
  config.default_url_options = {:exclude => [/^admin$/]}

That will exclude any “admin”-associated URLs from the Route object given to the Javascript code. The idea is that you might not want all the URLs in your project to be exposed to the client (when designing your app, however, it is advisable to assume that an attacker does have this list of paths). So, with the exclude key, we can omit certain paths using regular expressions.

Say you always want full paths (e.g. “”) rather than local paths (e.g. “/posts”). That’s easy too:

JsRoutes.setup do |config|
  config.prefix = ""

Note that there is no trailing slash.

Wrapping it Up

Writing Rails code in the modern, Javascript-driven web requires a lot of mental context switching. With JsRoutes, at least you don’t have to rethink the way you handle paths when you switch to the front-end parts of your codebase.



Learn Coding Online
Learn Web Development

Start learning web development and design for free with SitePoint Premium!

Get the latest in Ruby, once a week, for free.