Routing with Rails and Angular

Last updated 11 October 2014

There are a lot of great blog posts about setting up an app with Rails as the back-end and AngularJS as the front-end. You can find some here, here, or here. When it comes to routing, though, the best approach is unclear.

If you are using ngRoute (and you really should be to allow deep linking on your Angular app) your server should be able to handle requests like /blog/posts/1 and show the appropriate blog post. You can easily do this by just routing all requests to your main index page and let Angular handle the routing. But what urls should Angular use to fetch the post from the server? You could namespace all of the server responses like /api/blog/posts/1 but that doesn't really make sense. What you really want is to respond to .html requests by displaying the single-page Angular html and to respond to .json requests with the appropriate resource as json.

Rails makes this easy!

As anyone who has generated scaffolding with Rails know, it is easy to craft a different response whether it is .html or .json. Your controllers frequently look like:

def show
  @post = Post.find(params[:id])
  respond_to do |format|
    format.html # render the html view
    format.json # render the json view
  end
end

So, if I have my home page at static_pages#home I might write:

respond_to do |format|
  format.html { render 'static_pages/home' }
  format.json # rendering the show.json.erb file
end

Now you don't have to try to redirect all requests in your config/routes file or do anything crazy to properly respond to deep links.

This works fine, but I don't usually feel it necessary to create the .json.erb file for simple models and it also gets quite repetitive to have the same respond_to block in every controller action that takes a get request. Instead, I find that declaring a custom method in your ApplicationController that handles it for you:

def ng_respond(response_for_json)
  respond_to do |format|
    format.html { render 'static_pages/home' }
    format.json { render json: response_for_json.to_json }
  end
end

That way you can create controller actions like this:

def show
  @post = Post.find(params[:id])
  ng_respond(@post)
end

I hope this helps you with routing in your Rails/Angular apps.