This will create the Rails app and set up an API that the Ember app can consume.
$ rails new myapp --skip-bundle
# Specific to this task
gem 'ember-rails'
gem 'active_model_serializers'
gem 'coffee-rails'
gem 'pg'
$ rails g ember:bootstrap -g --javascript-engine coffee
in config/database.yml
development:
adapter: postgresql
encoding: unicode
database: myapp_development
username: USERNAME
password:
host: localhost
test:
adapter: postgresql
encoding: unicode
database: myapp_test
pool: 5
username: USERNAME
password:
host: localhost
Then run:
$ rake db:create
in config/routes.rb
namespace :api, path: '/api' do
resources :tasks
end
in initializers/inflections.rb
ActiveSupport::Inflector.inflections(:en) do |inflect|
inflect.acronym 'API'
end
add controllers/api/tasks_controller.rb
module API
class TasksController < ApplicationController
def index
tasks = Task.all
render json: tasks, status: 200
end
end
end
create the Task model
$ rails g model Task title:string completed:boolean
$ rake db:migrate
Add a couple of tasks using rails console
:
Task.create!(title: "Task 1"); Task.create!(title: "Task 2")
Start the server with rails s
, you should be able to visit http://localhost:3000/api/tasks and see:
{"tasks":[{"tasks":{"id":5,"title":"Task 1","completed":null,"created_at":"2014-08-10T08:58:02.901Z","updated_at":"2014-08-10T08:58:02.901Z"}},{"tasks":{"id":6,"title":"Task 2","completed":null,"created_at":"2014-08-10T08:58:02.905Z","updated_at":"2014-08-10T08:58:02.905Z"}}]}
in config/routes.rb
root 'site#index'
add controllers/site_controller.rb
class SiteController < ApplicationController
def index
end
end
add views/site/index.html.erb
<h1>Tasks app</h1>
$ rails g serializer task
in serializers/task_serializer.rb
class TaskSerializer < ActiveModel::Serializer
attributes :id, :title, :completed
end
Restart the Rails server to see the effect.
delete javascripts/application.js
$ rm app/assets/javascripts/application.js
add correct namespace to javascripts/store.js.coffee
Myapp.ApplicationAdapter = DS.ActiveModelAdapter.extend({
namespace: 'api'
})
in javascripts/router.js.coffee
Myapp.Router.map ()->
@resource 'tasks', path: '/'
add javascripts/routes/tasks_route.coffee
Myapp.TasksRoute = Ember.Route.extend
model: ->
return this.store.find('task')
add javascripts/models/task_model.coffee
Myapp.Task = DS.Model.extend
title: DS.attr 'string'
completed: DS.attr 'boolean'
add javascripts/templates/tasks.handlebars
Restart your server and visit http://localhost:3000/ and you should see the tasks.
update javascripts/router.js.coffee
Myapp.Router.map ()->
@resource 'tasks', path: '/', ->
@resource 'task', path: '/task/:task_id'
update javascripts/templates/tasks.handlebars to add a link-to and an outlet
<ul>
{{#each}}
<li>
{{#link-to 'task' this}}{{title}}{{/link-to}}
</li>
{{/each}}
</ul>
{{outlet}}
add javascripts/templates/task.handlebars
<h2>{{title}}</h2>
If you click a task link, it should show up below, where the outlet is. If you want the task to show up on its own page, just un-nest the resource and the entire template will be replaced when you click the link.
in Gemfile
group :development do
gem 'spring'
gem 'spring-commands-rspec'
end
group :development, :test do
gem 'rspec-rails', '~> 3.0.0'
gem 'capybara'
gem 'poltergeist'
end
install the gems and spring binstubs
$ bundle install && bundle exec spring binstub --all && spring stop
install rspec
$ rails generate rspec:install
check spring is running
$ bin/rspec
$ spring status
Tests should run faster now.
in spec/spec_helper.rb
def json(body)
JSON.parse(body, symbolize_names: true)
end
in spec/api/tasks_spec.rb
require "rails_helper"
RSpec.describe "the tasks API", :type => :request do
describe "listing tasks" do
it "responds successfully with an HTTP 200 status code" do
get '/api/tasks'
expect(response).to be_success
expect(response).to have_http_status(200)
end
it "returns the tasks" do
Task.create!(title: "Task 1", description: "Task 1 desc")
Task.create!(title: "Task 2", description: "Task 2 desc")
get '/api/tasks'
tasks = json(response.body)[:tasks]
task_titles = tasks.collect { |task| task[:name] }
expect(task_titles).to include("Task 1")
expect(task_titles).to include("Task 2")
end
end
end
in spec/spec_helper.rb
require 'capybara/poltergeist'
Capybara.javascript_driver = :poltergeist
add spec/integration/tasks_index_spec.rb
require "rails_helper"
RSpec.describe "the list of tasks", :type => :feature do
describe "viewing the list", js: true do
it "shows the tasks" do
Task.create!(title: "Task 1", description: "Task 1 desc")
Task.create!(title: "Task 2", description: "Task 2 desc")
visit '/'
expect(page).to have_text("Task 1")
expect(page).to have_text("Task 2")
end
end
end