Note: Make sure you're using Rails 4.1!

At my startup Service Route we've been building our app on Angular and Rails 4.1. I wanted to start sharing some our experiences on getting these two frameworks working together. All this post is going to cover is how to get them setup. As a plus we'll also get HTML5 mode routing setup so that Google can index and SEO your angular app! (More info on why this works here)

This tutorial isn't going to cover Ruby, Rails, or Angular basics. So if you're completely new to all of those, some things may not make sense, but you should still be able to follow along.

1) Create a new rails app

$ rails new angular_rails --database=postgresql

2) Get the database setup

$ cd angular_rails $ rake db:create $ rake db:migrate

3) Add two gems to the Gemfile

gem 'bower-rails' gem 'angular-rails-templates'

Bower is a kickass frontend package manager by the same people who did Twitter Bootstrap. It makes installing frontend dependencies a breeze. I was overjoyed when I saw someone had made it into a rake task. To get it up and running you need to make sure you have both Node.js and Bower installed. It takes a couple of minutes at most.

Angular Rails Templates is a helpful gem that makes working with angular templates far easier. It also kills the AJAX requests per template by leverage the template cache. This means less HTTP requests for your user and thus better performance. You'd honestly windup implementing what this package does even if you chose not to use it.

4) Install the gems

$ bundle install

5) Initialize Bower

$ rails g bower_rails:initialize json

This will give you a bower.json file in your project. What you'll do here is list the dependencies you need and bower will make them available to rails for you.

6) Open up bower.json and add the following keys/properties to the lib.dependencies:

{ "lib": { "name": "bower-rails generated lib assets", "dependencies": { "angular": "latest", "angular-route": "latest" } }, ... }

7) Back in the console, all we need to do now is run a rake task and we'll have all the dependencies!

$ rake bower:install

8) Go to app/assets/javascripts/application.js and add the following lines to the manifest before //= require_tree . and get rid of turbolinks

//= require turbolinks <--- get rid of this line //= require angular //= require angular-route //= require angular-rails-templates //= require_tree ../templates

This is going to pull in those dependencies and also make the /templates folder available for caching. Speaking of which...

9) Make a folder app/assets/templates/ . It will hold all of your angular templates.

10) If you've had the rails server, you need to stop and restart it to make sure those dependencies get added in.

Now we need to configure Rails to let Angular handle routing on the client side end and also allow for HTML5 Mode routing... and thus SEO goodness.

11) Open up config/routes.rb and add the following lines:

Rails.application.routes.draw do root 'application#index' get '*path' => 'application#index' ...

This is going to send all incoming requests to our index file and let angular handle them. The second line there allows you to refresh the page on routes and not have Rails confuse a client side refresh with a request to a resource.

Now we need to get the controller configured correctly

12) Open up app/controllers/application_controller.rb and add the following:

class ApplicationController < ActionController::Base ... protect_from_forgery with: :exception def index end end

This will send all requests to our index.html.erb we'll be making here in a second. Again, this allows Angular to handle the routing instead of Rails.

13) Create the file app/views/application/index.html.erb and put in the following:

<div ng-view=""></div>

This is where angular will dump its templates.

14) Open up app/views/layouts/application.html.erb and add ng-app="AngularRails" to the

<body ng-app="AngularRails"> ...

tag:

This is needed to initialize the angular application. Of course nothing will happen yet because we haven't created any angular code.

15) Create the file app/assets/javascripts/ng-app/app.js . ng-app/ is where our angular javascripts will live. Put the following code in app.js :

angular .module('AngularRails', [ 'ngRoute', 'templates' ]).config(function ($routeProvider, $locationProvider) { $routeProvider .when('/', { templateUrl: 'home.html', controller: 'HomeCtrl' }); $locationProvider.html5Mode(true); });

You'll notice that the template url is simply home.html. The way Angular Rails Templates works is that it treats your app/assets/templates/ folder as the root for your angular templates. So if we had a file at app/assets/templates/example/page.html.erb we'd reference it as example/page.html in our templateUrl in Angular. Take note of not including the ERB extension.

Now to create the respective html file and controller...

16) Create the file app/assets/javascripts/ng-app/controllers/home.js and put the following in it:

angular.module('AngularRails') .controller('HomeCtrl', function ($scope) { $scope.things = ['Angular', 'Rails 4.1', 'Working', 'Together!!']; });

17) Create the file app/assets/templates/home.html.erb and put in the following:

<h1>The Home View!</h1> <ul> <li ng-repeat="thing in things"> {{thing}} </li> </ul>

And everything should be ready to go!

The Git Repo

Here's what everything should look like at the end:

https://github.com/jcolemorrison/angular-rails-tutorial-part-1

In actual use

In our stack we're using Angular UI Router and Restangular instead of the default routing system and $resource. There's some more configuration required to get them up and working though.

Conclusion

Although there's nothing over the top complicated here, we couldn't find any step-by-steps of getting this setup simply. All Rails is going to be doing is acting as an API the majority of the time, but keeping it in the mix gives us other options if we need purely static pages.

If there's enough interest I'd be more than happy to write about setting up actual REST end points in Rails and connecting them to AngularJS.

As always, tell me if you see any problems or typos!