HomeRamblings  ⁄  ProgrammingJavaScript

Adding Google Analytics script to Sprockets

Published: January 30, 2014 (over 3 years ago)
Updated: about 2 years ago

Today, I wanted to add Google Analytics for tracking my website’s usage history. Rails 4.0 has an excellent assets pipeline that generally works well out of the box with little fuss, but when you try to do something outside adding another require to the “assets/javascripts/application.js.coffee” file, it gets a little more complicated to implement. Here, I show you exactly how to add Google Analytics as a coffeescripted script that is only loaded in the production environment.

Preamble

One of the things I don’t do is use sprockets’ “require_tree .” directive because this tends to pick up everything I have in the assets folders for every rendering and that’s just not necessary. Even though uglifier and sprockets does a good job of compressing and minifying the javascript code, I rarely need more than a handful of those assets on the front-side of things. I build web applications and the bulk of those assets are only used on the admin side. Things like WYSIWYG editors, Active Admin, Carrierwave (file/image uploads), and so on rarely need to be on the front-side of websites that I am typically building, yet these components can add up to quite a sizable download package even compressed and minified. For me, this means I regularly choose to eschew the easy out solution of calling “require_tree .” to pull in whole swaths of javascripts into my project’s views. So, lets take a look at how to do fine-grained control of your assets with sprockets.

The Google Analytics Script

Although not strictly necessary, I like as much of my JS in CoffeeScript as possible as it allows me to debug and fix more seamlessly. I wouldn’t turn a large library like jQuery into a CoffeeScripted version, but small scripts and jQuery plugins under 150 lines, I often do as I become the defacto maintainer of that specific version going forward. Using the fine tool over at http://js2coffee.org, I pasted the Google Analytics JavaScript in and got back the CoffeeScript version:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
((i, s, o, g, r, a, m) ->
  i["GoogleAnalyticsObject"] = r
  i[r] = i[r] or ->
    (i[r].q = i[r].q or []).push arguments_

  i[r].l = 1 * new Date()

  a = s.createElement(o)
  m = s.getElementsByTagName(o)[0]

  a.async = 1
  a.src = g
  m.parentNode.insertBefore a, m
) window, document, "script", "//www.google-analytics.com/analytics.js", "ga"
ga "create", "UA-123456789-1", "example.com"
ga "send", "pageview"

The above is saved to: app/assets/javascripts/google_analytics.js.coffee

Including in your view

Next, include it in your app/views/layouts/application.html.haml file with the javascript_include_tag helper:

1
2
3
4
5
6
7
8
9
10
!!!
%html
  %head
    %title Example Website
    = stylesheet_link_tag    "application", media: "all"
    = csrf_meta_tags
  %body
    = yield
    = javascript_include_tag "application"
    = javascript_include_tag "google_analytics" if production?

In the above, the last line is the line we just added and the “if production?” on that line is a simple helper method in the app/helpers/application_helper.rb file:

1
2
3
4
5
module ApplicationHelper
  def production?
    Rails.env == 'production'
  end
end

We’re not done, yet!

If you were to deploy with just the above, you’d find out very quickly, you’re not quite done as the views would render this:

1
2
<script src="/assets/application-f15feb4200e0d1db4963a00b28fbe9ca.js"></script>
<script src="/javascripts/google_analytics.js"></script>

Notice how the Google Analytics script isn’t prefixed with the assets path. If you were to check it in development mode (after removing the if production? guard), you’d see this:

1
2
3
4
<script type="text/javascript" src="/assets/jquery.js?body=1"></script>
<!-- several other includes suppressed for brevity here -->
<script type="text/javascript" src="/assets/application.js?body=1"></script>
<script type="text/javascript" src="/assets/google_analytics.js?body=1"></script>

In seeing the output above, you would think that because everything’s served from the assets folder, it should likewise be served from the assets folder on production. However, this isn’t the case, and its one of sprockets greatest mistakes, I believe. Code that is tested and functioning in development should be expected to behave correctly when deployed to production. I am a big believer in failing fast and loud rather than later and silently. Luckily, there’s a gem out there called ‘sprockets_better_errors’ that makes Sprockets behave just like this and give you fair warning that your code’s going to fail in production. The only downfall this gem has is that it surfaces all other gems that have trouble with their own assets pipelines – Active Admin, currently being one of those! However, its a great asset to finding assets related problems early on in development. Back to the problem at hand, it turns out that if sprockets is configured to pull in application.js.coffee and anything in its manifest, but nothing else – which means, when you take out the “require_tree .” line, our new-fangled google_analytics script won’t get pre-compiled by sprockets. The solution is to modify config/environments/production.rb and add the following line inside the config block:

1
2
3
4
ComingSoon::Application.configure do
  # Other lines omitted for brevity
  config.assets.precompile += ['google_analytics.js']
end

Notice that the file name is specified without the coffee extension! With this solution in place, you should notice that rake assets:precompile now generates the fingerprinted version of google_analytics.js file into your public/assets folder. Your view will now render with something like the following:

1
2
<script src="/assets/application-f15feb4200e0d1db4963a00b28fbe9ca.js"></script>
<script src="/assets/google_analytics-df845574fb2ba0fcbf892ecbdeae5107.js"></script>

Rails 4’s new assets pipeline processing has definitely stumped more than a few seasoned Rails developers, but sprockets does a comprehensive job of resolving many long-standing issues with having fully-expanded, individually included resources at development time that are seamlessly rolled up into one compressed/minified resource at production time. Hopefully, this brief article puts you on the right track to mastering sprockets on a more granular level.

comments powered by Disqus