Setting up Ember.js with Rails
Read in 5 minutes
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 your
config/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.
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 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.
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.
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.