Setting up Ember.js (ember-cli) with Rails
Read in 8 minutes
I received quite some feedback on my article about setting up Ember.js in Rails app, the most common being ember-cli.
ember-cli
is the canonical way of running Ember apps, confirmed by the RFC that formalizes the upcoming v2.0 release.
While globals-based apps will continue to work in 2.0, we may introduce new features that rely on either Ember CLI or ES6 modules. You should begin moving your app to Ember CLI as soon as possible.
—Tom Dale, The Road to Ember 2.0
So ember-cli is a big deal. And so I decided to try it out, but not directly. I still think keeping my workflow under Rails is more productive, so I’ll use the recommended ember-cli-rails gem.
Warning: This article has a previous version that uses ember-rails
instead. Read the original article.
Installation
Installing ember-cli
First, you’ll have to install Node.js or, even better, IO.js. So visit the project’s website and follow the instructions for your platform.
To install ember-cli, run npm install ember-cli -g
.
$ npm install ember-cli -g
$ ember -v
version: 0.1.12
node: 1.1.0
npm: 2.1.8
Notice that I’m using IO.js, so that’s why my Node version is listed as 1.1.0
. If you get similar output, then you’re good to go.
Configuring your Rails app
First, let’s remove things we won’t use from our Gemfile
. This includes turbolinks
and jquery-ujs
. You also have to add the ember-cli-rails
gem.
source 'https://rubygems.org'
gem 'rails', '4.2.0'
gem 'sass-rails', '~> 5.0'
gem 'uglifier', '>= 1.3.0'
gem 'ember-cli-rails'
You can install the dependencies with bundle install
.
Setting up your Rails app
The ember-cli-rails
will give you a generator called ember-cli:init
, that will basically create an initializer file. Go ahead and generate it.
$ rails g ember-cli:init
create config/initializers/ember.rb
You can use this initializer to setting up your Ember apps. By default it’s configured to use an application called frontend
that must live under app/frontend
.
EmberCLI.configure do |config|
config.app :frontend
end
You can define a different path, or even map multiple apps.
EmberCLI.configure do |config|
config.app :frontend, path: 'app/ember/frontend'
config.app :admin #=> path will be app/admin
end
For your Ember application, I suggest changing the app to something like :rails_root/frontend
. Adding to the app
directory will impact your performance in development mode, because Rails will track all files for auto-loading, even though this won’t be used. So for this example, I’m assuming your Ember app will live under :rails_root/frontend
.
EmberCLI.configure do |config|
config.app :frontend, path: Rails.root.join('frontend').to_s
end
To bootstrap your Ember app, let’s create a Rails controller/action. 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
.
Since you may use app/views/layouts/application.html.erb
for other things than just Ember, I recommend creating a new layout file at app/views/layouts/ember.html.erb
.
<!doctype html>
<html dir="ltr" lang="<%= I18n.locale %>">
<head>
<meta charset="UTF-8">
<title>Ember</title>
<%= stylesheet_link_tag 'frontend' %>
<%= include_ember_script_tags :frontend %>
</head>
<body>
<%= yield %>
</body>
</html>
For now, ember-cli-rails recommends using ember-cli just for JavaScript; that means that you should use asset pipeline for everything else, like images and CSS. So that’s why I’m using stylesheet_link_tag
instead of include_ember_stylesheet_tags
.
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-all
route 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
Creating an Ember app
Everything we’ve done so far was configuring Rails. Now it’s time to generate the Ember application. You’ll have to use the ember
command for this. From your Rails app root directory, run ember new frontend
.
$ ember new frontend --skip-git
version: 0.1.12
installing
create .bowerrc
create .editorconfig
create .ember-cli
create .jshintrc
create .travis.yml
create Brocfile.js
create README.md
create app/app.js
create app/components/.gitkeep
create app/controllers/.gitkeep
create app/helpers/.gitkeep
create app/index.html
create app/models/.gitkeep
create app/router.js
create app/routes/.gitkeep
create app/styles/.gitkeep
create app/templates/application.hbs
create app/templates/components/.gitkeep
create app/views/.gitkeep
create bower.json
create config/environment.js
create .gitignore
create package.json
create public/crossdomain.xml
create public/robots.txt
create testem.json
create tests/.jshintrc
create tests/helpers/resolver.js
create tests/helpers/start-app.js
create tests/index.html
create tests/test-helper.js
create tests/unit/.gitkeep
create vendor/.gitkeep
Installed browser packages via Bower.
Installed packages for tooling via npm.
You also need to install the ember-cli-rails-addon
NPM package. Do it from your Ember app directory.
$ cd frontend
$ npm install ember-cli-rails-addon --save-dev
ember-cli-rails-addon@0.0.11 node_modules/ember-cli-rails-addon
$ cd ..
Let’s check if everything works together. Create a file at frontend/app/templates/index.hbs
with the following content.
<p>
Fuck yeah! It works!
</p>
We need to create a CSS file for our Ember app. So, create app/assets/stylesheets/frontend.scss
with the following content.
// @import './frontend/**/*';
This means that all CSS for frontend
Ember app will live under app/assets/stylesheets/frontend
directory. Remember to update your config/initializers/assets.rb
file to include this file to the precompiling list.
Rails.application.config.assets.precompile += %w[ frontend.css ]
Fire up your server with rails server
and head to http://localhost:3000
. You must see a page like this:
Understanding ember-cli-rails
So, what exactly does ember-cli-rails do? In a few words, it runs ember
commands through a Rack middleware. When you visited http://localhost:3000
, ember-cli-rails issued the ember build
command, as you can see in your server log.
$ rails s
=> Booting WEBrick
=> Rails 4.2.0 application starting in development on http://localhost:3000
=> Run `rails server -h` for more startup options
=> Ctrl-C to shutdown server
[2015-02-07 22:37:06] INFO WEBrick 1.3.1
[2015-02-07 22:37:06] INFO ruby 2.2.0 (2014-12-25) [x86_64-darwin14]
[2015-02-07 22:37:06] INFO WEBrick::HTTPServer#start: pid=87021 port=3000
Started GET "/" for ::1 at 2015-02-07 22:37:07 -0200
version: 0.1.12
Building...
Build successful - 792ms.
Slowest Trees | Total
-------------------------------+----------------
Concat: Vendor | 139ms
SixToFive | 71ms
JSHint app- QUnit | 59ms
ES6Modules | 55ms
ES3SafeFilter | 53ms
Processing by EmberController#bootstrap as HTML
Rendered ember/bootstrap.html.erb within layouts/ember (1.5ms)
Completed 200 OK in 118ms (Views: 117.2ms)
Started GET "/assets/frontend/vendor-64e62ddc273c2f5847f30d698ca14b67.css?body=1" for ::1 at 2015-02-07 22:37:12 -0200
Started GET "/assets/frontend/frontend-64e62ddc273c2f5847f30d698ca14b67.css?body=1" for ::1 at 2015-02-07 22:37:12 -0200
Started GET "/assets/frontend/frontend-e07fffa094f820251c6586556d21c934.js?body=1" for ::1 at 2015-02-07 22:37:12 -0200
Started GET "/assets/frontend/vendor-a050afbf761cda6b6c9046c755b3dceb.js?body=1" for ::1 at 2015-02-07 22:37:12 -0200
Notice that the ember
process will be running in background until you stop your Rails server. This is useful, because ember-cli only compiles your Ember app when a file changes, making the whole process so much faster.
Although this integration is really helpful, it doesn’t mean you won’t ever run ember-cli directly; ember-cli has generators that will make you life easier, so you better off knowing the command-line’s API.
$ ember g -h
version: 0.1.12
Requested ember-cli commands:
ember generate <blueprint> <options...>
Generates new code from blueprints.
aliases: g
--dry-run (Boolean) (Default: false)
aliases: -d
--verbose (Boolean) (Default: false)
aliases: -v
--pod (Boolean) (Default: false)
aliases: -p
Available blueprints:
ember-addon:
ember-data <name>
ember-cli-qunit:
ember-cli-qunit <name>
ember-cli:
acceptance-test <name>
Generates an acceptance test for a feature.
adapter <name> <options...>
Generates an ember-data adapter.
--base-class
adapter-test <name>
Generates an ember-data adapter unit test
addon <name>
The default blueprint for ember-cli addons.
app <name>
The default blueprint for ember-cli projects.
blueprint <name>
Generates a blueprint and definition.
component <name>
Generates a component. Name must contain a hyphen.
component-test <name>
Generates a component unit test.
controller <name>
Generates a controller.
controller-test <name>
Generates a controller unit test.
helper <name>
Generates a helper function.
helper-test <name>
Generates a helper unit test.
http-mock <endpoint-path>
Generates a mock api endpoint in /api prefix.
http-proxy <local-path> <remote-url>
Generates a relative proxy to another server.
in-repo-addon <name>
The blueprint for addon in repo ember-cli addons.
initializer <name>
Generates an initializer.
initializer-test <name>
Generates an initializer unit test.
lib <name>
Generates a lib directory for in-repo addons.
mixin <name>
Generates a mixin.
mixin-test <name>
Generates a mixin unit test.
model <name> <attr:type>
Generates an ember-data model.
model-test <name>
Generates a model unit test.
resource <name>
Generates a model and route.
route <name> <options...>
Generates a route and registers it with the router.
--type=route|resource (Default: route)
aliases: -route (--type=route), -resource (--type=resource)
--path (Default: )
route-test <name>
Generates a route unit test.
serializer <name>
Generates an ember-data serializer.
serializer-test <name>
Generates a serializer unit test.
server <name>
Generates a server directory for mocks and proxies.
service <name>
Generates a service and initializer for injections.
service-test <name>
Generates a service unit test.
template <name>
Generates a template.
test-helper <name>
Generates a test helper.
transform <name>
Generates an ember-data value transform.
transform-test <name>
Generates a transform unit test.
util <name>
Generates a simple utility module/function.
util-test <name>
Generates a util unit test.
view <name>
Generates a view subclass.
view-test <name>
Generates a view unit test.
Another thing that’s worth mentioning is that some tasks can only be performed by npm
or bower
commands; there’s no alternative as a rake task.
So, make yourself comfortable with ember-cli, NPM and Bower. You’ll probably have to do this eventually.
Running tests
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.
All your Ember’s tests must be loaded from <your ember app>/tests
. When you generated the Ember app, some tests were generated too. You can run them by issuing rake ember-cli:test
(Rails app root) or ember test
(Ember app root).
$ cd frontend
$ ember test
version: 0.1.12
Built project successfully. Stored in "myapp/frontend/tmp/class-tests_dist-YU0yGWyj.tmp".
ok 1 PhantomJS 1.9 - JSHint - .: app.js should pass jshint
ok 2 PhantomJS 1.9 - JSHint - helpers: helpers/resolver.js should pass jshint
ok 3 PhantomJS 1.9 - JSHint - helpers: helpers/start-app.js should pass jshint
ok 4 PhantomJS 1.9 - JSHint - .: router.js should pass jshint
ok 5 PhantomJS 1.9 - JSHint - .: test-helper.js should pass jshint
1..5
# tests 5
# pass 5
# fail 0
# ok
To run tests in your browser, execute ember test --serve
and visit http://localhost:7357
.
One problem you’ll notice is that your app’s CSS won’t be loaded; remember that we’re using Rails Asset Pipeline to handle images and CSS. A quick fix while we don’t have an official solution is pointing the CSS to your development’s web server. Just change the file frontend/tests/index.html
and <link rel="stylesheet" href="assets/frontend.css">
to <link rel="stylesheet" href="http://localhost:3000/assets/frontend.css">
.
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
Having a totally different stack for your front-end has pros and cons. It’s great to have this separation when you have a front-end engineer that will hack Ember most of the time, but can be a pain point when you’re used to Rails and its workflow. Not to mention that the setup got way more complex than the one described by the original text.
ember-cli-rails is a nice start, but is still immature. In a perfect world you’d just use Rails and the asset pipeline. No ember-cli, no NPM, no Bower, but I don’t think that will ever happen.
So if you’re betting on Rails and Ember.js, make sure you get comfortable with ember-cli and consider using it without ember-cli-rails. Assume that Rails will be just an API and that you’re front-end is Ember, a completely different client.
You can found the source code for this example at Github.