At Rigor we’re always looking for technologies that will help improve our app, so when we started developing new reporting tools, we saw a great opportunity to give our front-end an upgrade with AngularJS. AngularJS is a framework developed by Google that makes creating interactive applications a breeze, and has the added benefit of integrating well with Ruby on Rails (our back-end framework).

There are a lot of resources out there to help merge Angular and Rails, but we were disappointed to find that most of these resources are dependent on the asset pipeline (which wasn’t introduced until Rails 3.1) and many are specifically tailored to Rails 4.

This might be sufficient for most developers, but a lot of applications (Rigor included) are built on older versions of Rails that don’t include the asset pipeline. This made creating directives (i.e. parts of an Angular app with their own functionalities and views) a bit tricky. We wanted to give these directives their own reusable templates, but without the asset pipeline, there was no obvious place for those templates to go.

To solve this problem, we first came up with some ideas about what the solution should look like:

No HTML inside the AngularJS app

Angular supplies a template option that accepts an HTML string to render, but this clutters the JavaScript code with HTML and means we can’t change the template without updating code. It’s always good practice to separate the app’s logic from the view, so this wasn’t an option for us.

Slim Templates

Slim is a template engine that we use throughout our app to keep our views clean and easy to understand. We wanted to continue using slim for our Angular templates.

Consistent File Structure

Since our Angular templates are working alongside Rails views and partials, we wanted to keep all views for a model in the same place, adhering to Rails’ file structure.

With these goals in mind, we decided to create a route for each directive that renders the Angular template as a partial. For directives relating to a specific model, we used that model’s controller.

Here’s an example from our app: the alertsTable directive displays a collection of alerts with a given status.

First, we created a slim template to display the alerts.

# app/views/reports/alerts/_alerts_table.html.slim
h2 Alerts
.row-fluid ng-repeat="alert in alerts"
  p {{ alert.description }}
  small {{ alert.timestamp }}

Next, we set up a route to render the partial. This will convert the template from slim to HTML so Angular can understand it.

# config/routes.rb
namespace :reports do
  get '/alerts/alerts_table', :to => 'alerts#alerts_table'
end
# app/controllers/reports/alerts_controller.rb
class Reports::AlertsController < ApplicationController
  def alerts_table
    render :partial => "reports/alerts/alerts_table"
  end
end

Now in our alertsTable  directive, all we need to do is set the templateUrl to the route we defined in the previous step.

// public/javascripts/alerts_dashboard_app.js
var app = angular.module('AlertsDashboardApp', []);
app.directive('alertsTable', function(){
  return {
    templateUrl: '/reports/alerts/alerts_table',
    scope: true
  };
});

And that’s it. Now we can define an alertsTable anywhere we want within our Angular app and it will serve up the right template.

Since we’re all about performance here at Rigor, it’s worth pointing out that while templateUrl triggers an additional HTTP request, AngularJS automatically loads all templates into its $templateCache the first time they’re rendered. No matter how many times you put a directive on a page, it will only request the HTML once.

This solution has worked out well so far, and it allows us to set up Angular apps quickly and seamlessly in Rails 3.0. We hope this was helpful if you are also trying to find ways to integrate AngularJS with Rails. Let us know if you have any suggestions for other AngularJS and/or Rails topics to discuss.