Using AngularJS with Rails 4 4/2/14

By Chris Johnson

Using AngularJS with Rails 4 should be pretty easy. Include the AngularJS library in your asset pipeline and start coding away. Unfortunately, it’s not quite that simple. You may have trouble…

Compressing AngularJS code in your asset pipeline

By default, Rails 4 compresses all of your JavaScript using UglifyJS. Sadly, UglifyJS clobbers AngularJS files, but the fix is a snap1. Go into config/environments/production.rb find the config.assets.js_compressor line and tell Rails to run the Uglifier without the mangle option:

config.assets.js_compressor = Uglifier.new(:mangle => false)

Processing Angular GET requests

To increase security, Rails will only process GET (and other form requests) if they pass along the proper cross-site request forgery (CSRF) token2. Rails is also particular about the Accept header when returning JSON. You can solve both issues by configuring your app’s global $httpProvider:

var app = angular.module('MyApp', []);

app.config(function($httpProvider) {
  var authToken = angular.element('meta[name="csrf-token"]').attr("content");
  $httpProvider.defaults.headers.common["X-CSRF-TOKEN"] = authToken;
});

In your AngularJS $http GET calls, you’ll also need to pass along a specific Content-Type header:

$scope.exampleAjax = function(ajaxUrl, var) {
  $http({
    method: 'GET',
    url: ajaxUrl + '?v=' + var,
    headers: {
      "Content-Type": "application/x-www-form-urlencoded; charset=UTF-8"
    }
  }).success(function(data) {
    console.log( data );
  });
};

If you’re going to leave Turbolinks enabled, you’ll need a way of re-bootstrapping your app after the new page content is loaded in3. Turbolinks has an event for this named page:load we can bind to after we define our Angular app:

var app = angular.module('MyApp', []);

$(document).on('ready page:load', function(){
  angular.bootstrap(document.body, ['MyApp']);
});

Now that we’re bootstrapping our app in our JavaScript, we need to remove the ng-app bootstrap directive from our HTML. So this:

<body ng-app="MyApp">

Can just be:

<body>

To be continued

I’ll be sure to update this post as I learn more about using AngularJS with Rails 4.

  1. Big thanks to Beryllium Work for the fix.

  2. If you’re using jQuery, Rails built-in helper will do this automatically.

  3. Thanks for fiedl and skalb on StackOverflow for the Turbolinks fix.