This article was last updated on May 28, 2013 and reflects the state of Ember (1.0.0-rc4) and the latest build of Ember Data (0.13) as of that date.
Lately I’ve been playing with Ember.js and I have really grown to love it. I get the same “AHA!” feeling I got building my first Rails app 7 years ago. Let’s see how to build a simple CRUD app using the RailsAPI as the backend. We’re going to build a new app and deploy to Heroku.
Part 1 - Getting Set Up
gem install rails-api
rails-api new ember-app
cd ember-app
Similar to the rails
command RailsAPI
comes with a rails-api
command which under the hood is just using the normal rails
CLI code
but overriding some of the templates generated. Out of the box
RailsAPI
won’t generate the asset pipeline directories
as there is still some
debate if it will use
Sprockets,
Rake-Pipeline or some
other solution. In this example we’re going to use Sprockets as it will
save us a lot of time. RailsAPI
is bundled with
ActionPack
which has Sprockets
as a dependency. All we need to do is add in the
directories
mkdir -p app/assets/{javascripts,stylesheets,images}
mkdir -p vendor/assets/{javascripts,stylesheets,images}
Now we need to copy in the vendored asset files. You can either build yourself our run the following to copy directly from my Github project
cd vendor/assets/javascripts
wget https://raw.github.com/bcardarella/ember-railsapi/master/vendor/assets/javascripts/ember-data.js
wget https://raw.github.com/bcardarella/ember-railsapi/master/vendor/assets/javascripts/ember.js
wget https://raw.github.com/bcardarella/ember-railsapi/master/vendor/assets/javascripts/jquery.js
wget https://raw.github.com/bcardarella/ember-railsapi/master/vendor/assets/javascripts/modernizr.js
cd ../../..
Note that if you’re a Mac user, just replace wget
(the Linux command) with curl -O
(the Unix command) on the above lines.
Let’s setup the directory structure for our Ember app
mkdir -p app/assets/javascripts/{controllers,models,views,templates}
And now we’ll setup the load order in our app/assets/javascripts/application.coffee
file
#= require modernizr
#= require jquery
#= require handlebars
#= require ember
#= require ember-data
#= require bootstrap
#= require_self
#= require store
#= require routes
#= require_tree ./controllers
#= require_tree ./models
#= require_tree ./templates
#= require_tree ./views
window.App = Ember.Application.create()
Add the routes.coffee
and store.coffee
files:
touch app/assets/javascripts/routes.coffee
touch app/assets/javascripts/store.coffee
And the app/assets/stylesheets/application.sass
file
@import 'bootstrap'
body
padding-top: 60px
That was a good amount of setup. Now we have the application structure for an Ember app in our asset pipeline. This will make things cleaner once we start coding.
Let’s setup the necessary gem dependencies in our Gemfile
. Just replace the entire contents with the following:
source 'https://rubygems.org'
ruby '2.0.0'
gem 'rails', '3.2.13'
gem 'rails-api'
gem 'thin'
gem 'active_model_serializers', :github => 'rails-api/active_model_serializers'
group :development, :test do
gem 'debugger'
gem 'sqlite3'
end
group :production do
gem 'pg'
end
group :assets do
gem 'sass-rails', '~> 3.2'
gem 'coffee-rails', '~> 3.2'
gem 'compass-rails'
gem 'uglifier'
gem 'bootstrap-sass', '~> 2.0.3.0'
gem 'handlebars_assets', '0.12.3'
end
group :development do
gem 'quiet_assets'
end
There are two gems to take note of:
- ActiveModelSerializers is a project that is written by the
Ember
core team which will normalize the JSON output for models in aRails
app. - HandlebarsAssets will allow the
AssetPipeline
to compile Handlebars templates which is required for Ember. There is the Ember-Rails gem which will also do this but I have foundHandlebarsAssets
to be a leaner solution.
After this, don’t forget to run bundle install
from the command line to pick up the gems we just added.
Let’s create a simple model and the serializer
rails-api g model User first_name:string last_name:string quote:text
rails-api g serializer User
Run ‘rake db:migrate’ to run the migration for our User model. Now open up app/serializers/user_serializer.rb
and add the fields that require serialization
class UserSerializer < ActiveModel::Serializer
attributes :id, :first_name, :last_name, :quote
end
Again, this will instruct Rails
to turn our ActiveRecord
object into a JSON
object properly normalized for Ember
.
Let’s write the Controller. Create and edit app/controllers/users_controller.rb
class UsersController < ApplicationController
def index
render json: User.all
end
end
Take note that we are inheriting ApplicationController
but in a RailsAPI
app ApplicationController
itself inherits from ActionController::API
instead of ActionController::Base
.
This basic controller will serve up all of our users to our Ember app. We’ll add more later.
Now let’s add some routes to config/routes.rb
EmberApp::Application.routes.draw do
class FormatTest
attr_accessor :mime_type
def initialize(format)
@mime_type = Mime::Type.lookup_by_extension(format)
end
def matches?(request)
request.format == mime_type
end
end
resources :users, :except => :edit, :constraints => FormatTest.new(:json)
get '*foo', :to => 'ember#index', :constraints => FormatTest.new(:html)
get '/', :to => 'ember#index', :constraints => FormatTest.new(:html)
end
A few things are happening here:
- We are constraining against the format with a custom
FormatTest
class. We only want to map certain routes toJSON
requests and certain routes toHTML
requesets. - The
get '*foo'...
will greedily match all routes except/
so we have the following line. We want to direct allHTML
requests to a singlecontroller#action
. I will go into the reason why in a bit.
So let’s create that Ember
controller. This will act as the primary application serving controller that is hit when people visit the app. Create and edit app/controllers/ember_controller.rb
class EmberController < ActionController::Base; end
Note that we are inheriting from ActionController::Base
this time and not ApplicationController
. This is so that the controller actions can respond to non JSON
requests.
Now we will add the view in app/views/ember/index.html.erb
<!DOCTYPE html>
<html lang='en'>
<head>
<%= stylesheet_link_tag :application, :media => :all %>
<%= javascript_include_tag :application %>
<title>Title</title>
</head>
<body>
</body>
</html>
That is all the view that your Ember app will need. Ember will automatically attach its own default template to the <body>
tag.
Let’s add some data to db/seeds.rb
User.create(:first_name => 'William', :last_name => 'Harrison', :quote => "I'm just singin' in the rain!")
User.create(:first_name => 'Abraham', :last_name => 'Lincoln', :quote => "I'd like to see a show tonight.")
Now run your migrations and seed
rake db:migrate db:seed
Ok, now our app is in a good spot to start developing an Ember app with. Let’s review what we did
- Generated a new app using
rails-api
- Set up the javascript and stylesheet assets
- Wrote a very simple JSON API for returning all users
In Part 2 we’ll build the Ember app itself.