Raw Syntax

The stuff programs are made of

How to Set Up Angular With Rails

Permalink

originally posted on the Intridea blog here: http://www.intridea.com/blog/2014/9/25/how-to-set-up-angular-with-rails

To get started lets create a new rails app.

gem install rails -v 4.1
rails new angular_example

In this app, I chose not to use turbolinks. It's possible to use Angular with Rails and turbolinks, but the Angular app bootstrap process is more complex. I find that turbolinks and Angular serve the same purpose, which is to make the app respond faster. Adding turbolinks, in addition to Angular, adds a lot of complexity and not much benefit.

Remove Turbolinks

Removing turbolinks requires removing it from the Gemfile.

gem 'turbolinks'

Remove the require from app/assets/javascripts/application.js

//= require turbolinks

Add AngularJS to the Asset Pipeline

In order to get Angular to work with the Rails asset pipeline we need to add to the Gemfile:

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

Next, we can install these gems into our bundle.

bundle install

We added bower so that we can install the AngularJS dependency.

rails g bower_rails:initialize json

When adding Angular to bower.json, I prefer to specify the most recent version rather than going with the "latest". This avoids having your app randomly break when a new version is released and your bower installs again.

{
"lib": {
"name": "bower-rails generated lib assets",
"dependencies": {
"angular": "v1.2.25"
}
},
"vendor": {
"name": "bower-rails generated vendor assets",
"dependencies": {
}
}
}

Now that bower.json is setup with the right dependencies, let's install them:

bundle exec rake bower:install

Organize the Angular App

At this point we'll create the following folder structure in app/assets/javascript/angular-app:

templates/
modules/
filters/
directives/
models/
services/
controllers/

This structure is only a convention and is not enforced by Angular (unlike file naming and organization in Rails). This project structure allows for a single web app to be easily composed of multiple smaller Angular modules rather than one giant Angular app for the whole site.

In app/assets/javascripts/application.js add Angular, the template helper, and the Angular app file structure. That file should now read like this:

//= require jquery
//= require jquery_ujs
//= require angular
//= require angular-rails-templates
//= require angular-app/app
//= require_tree ./angular-app/templates
//= require_tree ./angular-app/modules
//= require_tree ./angular-app/filters
//= require_tree ./angular-app/directives
//= require_tree ./angular-app/models
//= require_tree ./angular-app/services
//= require_tree ./angular-app/controllers

Bootstrap the Angular App

Next, we'll setup the Angular app bootstrapping. Create app/assets/javascripts/angular-app/app.js.coffee:

@app = angular.module('app', [
# additional dependencies here, such as restangular
'templates'
])
# for compatibility with Rails CSRF protection
@app.config([
'$httpProvider', ($httpProvider)->
$httpProvider.defaults.headers.common['X-CSRF-Token'] = $('meta[name=csrf-token]').attr('content')
])
@app.run(->
console.log 'angular app running'
)

Then, we'll create an Angular module at app/assets/javascripts/angular-app/modules/example.js.coffee.erb

@exampleApp = angular
.module('app.exampleApp', [
# additional dependencies here
])
.run(->
console.log 'exampleApp running'
)

Following the Angular module, we'll create an Angular controller for this app at app/assets/javascripts/angular-app/controllers/exampleCtrl.js.coffee

angular.module('app.exampleApp').controller("ExampleCtrl", [
'$scope',
($scope)->
console.log 'ExampleCtrl running'
$scope.exampleValue = "Hello angular and rails"
])

Now we need to add a route to Rails to pass control over to Angular. In config/routes.rb:

Rails.application.routes.draw do
get 'example' => 'example#index'
end

Next, we'll generate the Rails controller to respond to that route:

rails g controller Example

In app/controllers/example_controller.rb:

class ExampleController < ApplicationController
def index
end
end

In the view we need to specify which Angular app, and which Angular controller will drive this page.

In app/views/example/index.html.erb:

<div ng-app='app.exampleApp' ng-controller='ExampleCtrl'>
<p>Value from ExampleCtrl:</p>
<p>{{ exampleValue }}</p>
</div>

To view the app, start your Rails server and visit http://localhost:3000/example

You can find the code generated here https://github.com/rawsyntax/rails-angular-example

Comments