Ler blog em Português

Setting up Ember.js with Rails

Read in 5 minutes

Ember.js

Ember.js is a client-side framework that aims single-page applications. It has several tools to abstract the most common patterns. Following the Convention Over Configuration concept, Ember reduces boilerplates for common things, freeing the developer to focus on what really matters: the application.

The most used tool for running Ember apps nowadays is ember-cli. Written with Node.js, generates files and runs the application. Ember-CLI comes with some nice features like asset pipeline and ES6 transpiling. But even with all these features, sometimes you just want to keep your workflow and use Rails.

In this article you’ll see how to set up Ember in a Ruby on Rails app, with testing support using QUnit.

Warning: This article has a new version that uses ember-cli-rails instead. Read the new article.

Installation

To install Ember in your Rails app, just add some gems to your Gemfile. Since jQuery is required, I’ll use Rails Assets, a proxy between Rubygems/Bundler and Bower, so I can have the latest version.

This is how your Gemfile looks like for Rails 4.2 and Ember 1.9.

source 'https://rubygems.org'
source 'https://rails-assets.org'

gem 'rails', '4.2.0'
gem 'sass-rails', '~> 5.0'
gem 'uglifier', '>= 1.3.0'
gem 'ember-rails'
gem 'ember-source', '~> 1.9.0'
gem 'rails-assets-jquery'

You can install the dependencies with bundle install.

Setting up the project

Now is the time to generate your Ember app. Just use the rails generate command. You can also specify your app’s namespace by using the -n switch.

$ rails g ember:bootstrap -n MyApp
    insert  app/assets/javascripts/application.js
    create  app/assets/javascripts/models
    create  app/assets/javascripts/models/.gitkeep
    create  app/assets/javascripts/controllers
    create  app/assets/javascripts/controllers/.gitkeep
    create  app/assets/javascripts/views
    create  app/assets/javascripts/views/.gitkeep
    create  app/assets/javascripts/routes
    create  app/assets/javascripts/routes/.gitkeep
    create  app/assets/javascripts/helpers
    create  app/assets/javascripts/helpers/.gitkeep
    create  app/assets/javascripts/components
    create  app/assets/javascripts/components/.gitkeep
    create  app/assets/javascripts/templates
    create  app/assets/javascripts/templates/.gitkeep
    create  app/assets/javascripts/templates/components
    create  app/assets/javascripts/templates/components/.gitkeep
    create  app/assets/javascripts/mixins
    create  app/assets/javascripts/mixins/.gitkeep
    create  app/assets/javascripts/adapters
    create  app/assets/javascripts/adapters/.gitkeep
    create  app/assets/javascripts/codeplane.js
    create  app/assets/javascripts/router.js
    create  app/assets/javascripts/store.js
    create  app/assets/javascripts/adapters/application_adapter.js

Open app/assets/javascripts/application.js and remove things like jquery-ujs and turbolinks. This is how you should do it:

//= require jquery
//= require handlebars
//= require ember
//= require ember-data
//= require_self
//= require ./my_app

MyApp = Ember.Application.create();

You also have to create a controller/action that will bootstrap your Ember application. You can go with EmberController#bootstrap. You don’t have add anything to the app/views/ember/bootstrap.html.erb.

class EmberController < ApplicationController
  def bootstrap
  end
end

Notice that you don’t have to specify the EmberController#bootstrap method, but I like the visibility. Again, remember to create a blank file at app/views/ember/bootstrap.html.erb.

Now it’s time to set up our Rails routes. Ember has support for history.pushState; This means that every time you visit a route, the URL will change, instead of using the #! scheme. You’ll need a _catch-allroute for this to work, so update yourconfig/routes.rb` to something like this:

Rails.application.routes.draw do
  root 'ember#bootstrap'
  get '/*path' => 'ember#bootstrap'
end

Now create a file at app/assets/javascripts/templates/index.hbs so we can see that everything is working as expected.

<h1>Ember</h1>
<p>Fuck yeah! It works!</p>

Finally fire up your server with rails server and head to http://localhost:3000. You see the following page if you get it right.

Ember.js in a Ruby on Rails app

Setting up the test environment

Ember has integration with QUnit. So here’s a tip: use it! Otherwise you won’t be able to use all built-in helpers. You also have way more documentation about Ember + QUnit than with any other framework.

Setting up Rails, Ember and QUnit used to be a complicated task; not anymore! I wrote a JavaScript test runner for Rails apps that supports Ember, QUnit, Jasmine and Mocha. Just add test_squad to your Gemfile.

source 'https://rubygems.org'
source 'https://rails-assets.org'

gem 'rails', '4.2.0'
gem 'sass-rails', '~> 5.0'
gem 'uglifier', '>= 1.3.0'
gem 'ember-rails'
gem 'ember-source', '~> 1.9.0'
gem 'rails-assets-jquery'

group :development, :test do
  gem 'test_squad'
end

You can bootstrap the test environment by running the rails generate command.

$ rails generate test_squad:install --framework ember
    create  test/javascript/unit
    create  test/javascript/unit/router_test.js
    create  test/javascript/routes
    create  test/javascript/routes/.keep
    create  test/javascript/components
    create  test/javascript/components/.keep
    create  test/javascript/views
    create  test/javascript/views/.keep
    create  test/javascript/models
    create  test/javascript/models/.keep
    create  test/javascript/test_helper.js
   gemfile  group :development, :test
    append  Gemfile
   gemfile  rails-assets-qunit
    append  Gemfile
    source  https://rails-assets.org
     exist  test/javascript
    create  test/javascript/test_squad.rb

The generator will detect if you’re running RSpec or TestUnit and will create the structure at spec/javascript or test/javascript.

You may need to modify the test helper file, setting your app’s namespace. It will use your Rails application name by default.

//= require application
//= require_self
//= require_tree ./components
//= require_tree ./models
//= require_tree ./routes
//= require_tree ./unit
//= require_tree ./views

// Set the application.
App = MyApp;

// Set up Ember testing.
App.rootElement = '#ember-testing';
App.setupForTesting();
App.injectTestHelpers();

The test_squad gem has asset pipeline support, so feel free to use CoffeeScript if you like it.

You can run tests in your browser or, even better, your terminal.

Running tests in your browser

First change your config/routes.rb to add the testing route. This is required only if you’re using the catch-all route and Ember’s history.pushState integration.

Rails.application.routes.draw do
  root 'ember#bootstrap'
  get :tests, to: 'test_squad#tests' unless Rails.env.production?
  get '/*path' => 'ember#bootstrap'
end

To run the tests, just start the server in development mode and visit http://localhost:3000/tests.

Running tests in the browser

Running tests in your terminal

First, you need to install Phantom.js. Mac users can do it with Homebrew.

$ brew install phantomjs

If you’re not using Mac, see how you can install Phantom.js.

Just use the rake test_squad command to run all tests.

Running tests in the terminal

Extending QUnit

By installing ember-qunit, you’ll be able to use some additional helpers for testing components and models.

Again, we’ll use Rails Assets for this. Add rails-assets-ember-qunit to your Gemfile and install this new dependency with bundle install.

source 'https://rubygems.org'
source 'https://rails-assets.org'

gem 'rails', '4.2.0'
gem 'sass-rails', '~> 5.0'
gem 'uglifier', '>= 1.3.0'
gem 'ember-rails'
gem 'ember-source', '~> 1.9.0'
gem 'rails-assets-jquery'

group :development, :test do
  gem 'test_squad'
  gem 'rails-assets-qunit'
  gem 'rails-assets-ember-qunit'
end

Load ember-qunit by requiring the library in your test_helper.js file.

//= require application
//= require ember-qunit/dist/globals/main
//= require_self
//= require_tree ./components
//= require_tree ./models
//= require_tree ./routes
//= require_tree ./unit
//= require_tree ./views

// Set the application.
App = MyApp;

// Set up ember-qunit
emq.globalize();
App.Resolver = Ember.DefaultResolver.extend({namespace: App});
setResolver(App.Resolver.create());

// Set up Ember testing.
App.rootElement = '#ember-testing';
App.setupForTesting();
App.injectTestHelpers();

And your done! Now you have helpers like moduleFor, moduleForComponent and moduleForModel, so don’t forget to read the docs.

Installing Ember Inspector

If you want to develop Ember apps, make yourself a favor and install Ember Inspector, a Chrome extension that can inspect your app. You check objects, see rendering times, and more.

Ember Inspector

Wrapping up

Most applications will have different clients like a web version, mobile (E.g. iOS, Android) and, maybe, a CLI, not to mention SDKs for different languages. The only possible-sane way of doing this is by having an API for all clients. Ember wants to be the final client for web applications (and maybe mobile).

Will it make it?

You can found the source code for this example at Github.