Turbolinks — How to organize your Javascript code

Alessandro Rodi
3 min readJul 21, 2016

Since Rails embraced Turbolinks nobody explained to you how to organize your Javascript properly and, after a while, you probably decided to remove Turbolinks completely from your project because it saved you a lot of pain.

In this article I will try to give you few hints on how to organize your javascript properly, quit your headaches and not hearing you complaining about Turbolinks anymore.

Organize your code!

We are Rails developers so we like convention over configuration. Let’s try to have a mechanism which will allow us to use this approach when organizing our Javascript code.

  • We want page specific code which will get executed only on a specific page;
  • We want to create a coffeescript file (and a coffeescript class) called like the page which will get executed automatically when the page is loaded;
  • When we have a new page we just need to create a coffeescript class which follows our convention and will be executed without any further configuration.

Our convention here will be ControllernameActionname. Every class will have then the following format:

blogs_new.coffeeclass @BlogsNew
constructor: ->
alert(‘New Blog!’)

And we want this code to be executed when the user is on the /blogs/new page.

First of all define a data- attribute attached to the body of the page which will give us exactly that name:

application.html.slim
html
head
...all your head stuff here...
body[data-page="#{body_page_name}"]
= yield

and the helper:

application_helper.rb
module ApplicationHelper
def body_page_name
@body_page_name ||=[controller_name.camelcase.gsub('::',''),action_name.camelcase].join
end
end

If we refresh our page we will see it working:

<body data-page=”BlogsNew”>

So now every page will have its data-page attribute which contains the name of the coffeescript class we want to execute. Let’s execute it!

I usually create a per_page subfolder in the assets/javascript folder for the page classes where I create my files. In this case:

blogs_new.coffeeclass @BlogsNew
constructor: ->
alert(‘New Blog!’)

Then I have the following coffeescript class which does all the magic in the main assets/javascript folder.

class Init
constructor: ->
page = “#{$(‘body’).data(‘page’)}”
@execute_page_js(page)
execute_page_js: (page) ->
if ‘function’ is typeof window[page]
klass = window[page]
new klass()
$(document).on ‘turbolinks:load’, ->
new Init()

What does it do?

The Init class, when instantiated, fetches the data-page attribute from the body:

page = “#{$(‘body’).data(‘page’)}”

it then checks if a class with that name is defined:

if ‘function’ is typeof window[page]

and executes it:

klass = window[page]
new klass()

At the end, we use the turbolinks:load event to execute the Init class on every page.

Turbolink 2 Notes

If you are using an old Turbolinks version just replace the following:

$(document).on ‘turbolinks:load’, ->
new Init()

with:

$ ->
new Init()
$(document).on ‘page:load’, ->
new Init()

Now load everything in the assets/javascrit/application.js file and reload your page!

application.js//= require init
//= require_tree ./per_page

This will execute this code only in this page, only once, and both on browser refresh or Turbolinks visit.

As an extra feature you can obviously override the default convention and declare explicitly the name of the Javascript file you want to load for a page.

So, for example, if this form gets posted but the server replies with a validation error you will end up with a different data-page attribute:

<body data-page=”BlogsCreate” cz-shortcut-listen=”true”>

To solve that you can explicitly define the @body_page_name attribute either in the controller or directly in the page.

I hope it helps. Please comment if you need clarification or any addition.

Here you can find the repository with the code: https://github.com/coorasse/turbolinks-example

Here is a potato:

--

--

Alessandro Rodi

Open Source Software Engineer at Renuo AG. Located in Zürich. I do stuff. Sometimes.