God Damn You Ryan

The Blog of Ryan MacInnes. Web developer and cool dude.

July 27th, 2013

Rails 4 Turbolinks and Backbone

I spent the last hour or so trying to make the backbone.js router and turbolinks play nicely on my new rails 4 app.

Turns out it was fairly straightforwards, but I had to learn a bit more about how Backbone.history works

Here's what I did:

With Turbolinks, you only get a document.ready event on the initial page load. Since turbolinks reloads the "body" tag, if you don't have your js in the body tag you won't reload them, and therefore won't get another document.ready call.

This is what my base backbone file looked like (in coffeescript of course):

# app/assets/javascripts/summerland.js.coffee

window.Summerland =
  Models: {}
  Collections: {}
  Views: {}
  Routers: {}
  initialize: ->
    new Summerland.Routers.Application
    Backbone.history.start pushState: true

$(document).ready ->
  Summerland.initialize()

The problem here is that the router only gets called on document.ready, so when you click a link, the page loads via turbolink, and the router doesn't get called again.

Luckily turbolinks creates a new event called 'page:load' that we can take advantage of.

Unfortunately, you can't just call the router again instead, you have to stop the history and then start it again, like so:

# app/assets/javascripts/summerland.js.coffee

window.Summerland =
  Models: {}
  Collections: {}
  Views: {}
  Routers: {}
  initialize: ->
    new Summerland.Routers.Application
    Backbone.history.start pushState: true

$(document).ready ->
  Summerland.initialize()

$(document).on 'page:load', ->
  Backbone.history.stop()
  Summerland.initialize()

This should initialize the router and history normally on your initial pageview, and then restart the history on subsequent link visits.

Seems to work so far!