Outline

One of the most handy features of rails is its asset pipeline which runs on sprockets. This is what allows us to use the require syntax at the beginning of our javascript/css files so that they'll be concatenated in production. It also allows us to easily drop in gems to compile any assets that need processing (such as less or coffeescript). You can read more about the asset pipeline at this official Rails guide.

Using Bower to manage dependencies

Bower is a command line utility that lets us manage our front-end dependencies with a bower.json file (think Gemfiles for front-end). It also integrates with the asset pipeline pretty well. Bower requires Node.js and git, so be sure to have git and npm on your system and run npm install -g bower if you haven't already.

Now we can run bower init to generate our initial bower.json file. You can just keep hitting enter and go with the default options.
Next, let's create a .bowerrc file in the root our Rails project. This is a configuration file for bower where we'll specify where we want our dependencies installed. We'll save them in vendor/assets/bower_components by providing the following configuration:
{
  "directory":"vendor/assets/bower_components"
}
Then, run bower install angular angular-ui-router bootstrap --save to install our frontend dependencies. The --save flag automatically adds them to bower.json.

Now that we have our dependencies installed locally, we can use sprockets directives to require them in application.js/css. Sprockets will automatically require the right file based off of the package name, as long as that package's bower.json has its main attribute set properly. Let's update application.js and application.css, and then remove the cdn links in our layout.

Require angular and angular-ui-router in application.js
//= require angular
//= require angular-ui-router
//= require_tree .

If you already tried *= require bootstrap in app/assets/stylesheets/application.css, you may have noticed that your Rails app throws an exception. This is because Bootstrap's bower.json has a .less file in its main attribute, which our project doesn't currently support. We can get around this by requiring the path to the bootstrap.css file in the bower_components folder instead (you won't need the bower_components as part of the path as sprockets should automatically look in vendor/assets/bower_components).

require bootstrap/dist/css/bootstrap in application.css
 *= require bootstrap/dist/css/bootstrap
 *= require_tree .

Finally, we'll clean up the <head> section of our layout so it looks like the rails default:
<head>
  <title>FlapperNews</title>
  <%= stylesheet_link_tag    'application', media: 'all' %>
  <%= javascript_include_tag 'application' %>
  <%= csrf_meta_tags %>
</head>

Now when we load the page, all of our javascript and css dependencies should be loaded from our vendored components, and they'll be concantenated and minified with the rest of our assets in production.

Note that if you want to use implicit dependency injection in angular, you'll want to install the ngannotate-rails gem so your javascript won't break during minification.

Avoid installing front-end dependencies in multiple places when you're using bower, as this could lead to the wrong file being required (for example, if you had the angularjs-rails in your Gemfile AND angular in your bower.json).

There's also a bower-rails gem if you prefer a more Gemfile-like syntax to your bower.json and rake tasks that wrap the bower commands, however, this will be another dependency in your Gemfile, and also requires Bower to be installed via npm.

Moving Angular Templates into the Asset Pipeline and Structuring the javascripts Folder

Right now all of our Angular templates are inlined in our application's layout. This is fine for now, but can become hard to organize as we add more views to our app. Luckily, there is a gem called angular-rails-templates that takes html templates and compiles them into javascript files that insert our templates into Angular's $templateCache. This allows us to move our templates into the app/assets/javascripts folder while referencing them in our app using the same syntax. We'll be grouping our files in the javascripts folder by feature. Having templates and javascript in the same folder may seem weird if you're used to Rails' directory structure, but it will make our project easier to navigate. See #1 in this list of top AngularJS mistakes.

Keep in mind that because this gem is changing HTML files to to javascript files, you want to avoid having two assets of the same basename (for example, posts.html and posts.js) in the same folder as sprockets will end up overwriting one of the files.

Let's install the angular-rails-templates gem and move the templates for the posts and home state from within the <script> tags in application.html.erb to HTML files in our javascripts folder. We can then remove the script tags in our layout, leaving us with a pretty clean application.html.erb.

Add gem 'angular-rails-templates' to your Gemfile
Run bundle install
require angular-rails-templates in your application.js after angular
Inject the templates module into our Angular app
angular.module('flapperNews', ['ui.router', 'templates'])
.config([
...
Create new folders home and posts within the javascripts folder
Move the /home.html template from application.html.erb to a new file _home.html inside the home folder you just created.
Move the /posts.html template from application.html.erb to a new file _posts.html inside the posts folder you just created.

Once we move our templates, we'll need to update the templateUrls in app.js in order to reflect the new paths to our templates. Note that the leading slash has been removed.

The leading underscore we used in our new HTML file names is a common practice used to show that the file contains a partial and not a full html file (it also helps us avoid asset path collisons mentioned earlier).

You are also able to change the HTML files to have the .html.erb extension and use erb tags to include images from the asset pipeline, but be aware that the ruby environment in the assets folder is separate from the rest of the application, and you should only be using sprockets helpers such as image_path or asset_path when mixing javascript and erb.

Update templateUrl for the home state in app.js to home/_home.html
      templateUrl: 'home/_home.html',
Update templateUrl for the posts state in app.js to posts/_posts.html
      templateUrl: 'posts/_posts.html',

While we're in app.js, let's take the time to split out our Angular services and controllers into separate files as well.

Move posts service from app.js to posts/posts.js
angular.module('flapperNews')
.factory('posts', [function(){
...
Move MainCtrl from app.js to home/mainCtrl.js
angular.module('flapperNews')
.controller('MainCtrl', [
'$scope',
...
Move PostsCtrl from app.js to posts/postsCtrl.js
angular.module('flapperNews')
.controller('PostsCtrl', [
'$scope',
...

The resulting javascripts folder should look something like this:

javascripts
||- home/
||__||- _home.html
||__||- mainCtrl.js
||- posts/
||__||- _posts.html
||__||- posts.js
||__||- postsCtrl.js
||- app.js
||- application.js

This should leave our app.js file with just our app declaration and config function. If we check our app in the browser, our app should still be fully functionaly with all of our files organized and going through the asset pipeline. Now that we have our front-end fully integrated with the asset pipeline, let's start building an API with Rails for our app to interface with so we can get persistent data.

 

I finished! On to the next chapter