SlideShare a Scribd company logo
1 of 65
Download to read offline
Crossing the Bridge:Crossing the Bridge:
Connecting Rails and your Front-endConnecting Rails and your Front-end
FrameworkFramework
@danielspecs@danielspecs
This is what we're trying to avoidThis is what we're trying to avoid
Instead we want thisInstead we want this
A GameplanA Gameplan
Understand the tradeoffs you'll make
Deeply integrate your framework with Rails
Share data in a consistent and maintainable way
Daniel SpectorDaniel Spector
Software Engineer at Lifebooker
@danielspecs
spector.io
Flatiron School
Rails/Javascript/Swift/Clojure
What are youWhat are you
getting yourselfgetting yourself
into?into?
Javascript. Wat.Javascript. Wat.
> [] + {}
=> [object Object]
> {} + []
=> 0
Courtesy of Alex Matchneer
Always thinkAlways think
about theabout the
bigger picturebigger picture
You will encounter a lot ofYou will encounter a lot of
tradeoffs.tradeoffs.
Some of the fun thatSome of the fun that
awaits...awaits...
Duplicated modelsDuplicated models
Separate codebasesSeparate codebases
ComplexityComplexity
But myBut my
clients/customers/formerclients/customers/former
cat's owner demands it!cat's owner demands it!
Er, no.Er, no.
What do people want?What do people want?
Maintainable,Maintainable,
sustainable,sustainable,
performantperformant
applicationsapplications
But now that you'veBut now that you've
been warned...been warned...
Holy s**t canHoly s**t can
you make someyou make some
awesomeawesome
applications.applications.
RecapRecap
Never lose sight of the ultimate goalNever lose sight of the ultimate goal
Understand the tradeoffs that willUnderstand the tradeoffs that will
comecome
There may be a solutionThere may be a solution
Now, let's dive inNow, let's dive in
What we're going to be building:What we're going to be building:
TodoMVC on RailsTodoMVC on Rails
Scaffolding out the same application in each ofScaffolding out the same application in each of
the frameworks makes it easy to referencethe frameworks makes it easy to reference
The Frameworks:The Frameworks:
Now let's have a lookNow let's have a look
at Angularat Angular
Developed by GoogleDeveloped by Google
Two-way data bindingTwo-way data binding
Dependency InjectionDependency Injection
But... Angular 2But... Angular 2
First, let's get ourFirst, let's get our
Rails project API readyRails project API ready
# app/controllers/api/todos_controller.rb
class Api::TodosController < ApplicationController
respond_to :json
def index
@todos = Todo.all
render json: @todos
end
def create
@todo = Todo.create(todo_params)
render json: @todo
end
private
def todo_params
params.require(:todo).permit(:item)
end
end
# config/routes.rb
namespace :api, :defaults => {:format => :json} do
resources :todos, only: [:index, :create]
end
# app/models/todo.rb
class Todo < ActiveRecord::Base
end
There's no official AngularThere's no official Angular
integration with Rails...integration with Rails...
So that's a perfect opportunity toSo that's a perfect opportunity to
try out Bower.try out Bower.
Created by Twitter
One centralized location for packages
Can be integrated with Rails via the bower-rails gem
$ npm install -g bower
# Gemfile
gem "bower-rails", "~> 0.9.2"
$ rails g bower_rails:initialize
# Bowerfile
# Puts to ./vendor/assets/bower_components
asset "angular"
asset "angular-resource"
asset "angular-route"
How can we manageHow can we manage
our client-side dataour client-side data
to make it easy toto make it easy to
work with?work with?
ngResource is an optional libraryngResource is an optional library
to map basic CRUD actions toto map basic CRUD actions to
specific method calls.specific method calls.
Let's scaffold out a basicLet's scaffold out a basic
Angular and see how we canAngular and see how we can
integrate ngResourceintegrate ngResource
// app/assets/main.js
// This is the main entry point for our application.
var Todo = angular
.module('todo', ['ngResource', 'ngRoute'])
.config(['$routeProvider', '$httpProvider', function($routeProvider, $httpProvider) {
// We need to add this for Rails CSRF token protection
$httpProvider.defaults.headers.common['X-CSRF-Token'] =
$('meta[name=csrf-token]').attr('content');
// Right now we have one route but we could have as many as we want
$routeProvider
.when("/",
{templateUrl: "../assets/index.html",
controller: "TodoCtrl"})
}]);
# config/application.rb
config.assets.paths << "#{Rails.root}/app/assets/templates"
Now we can set up our factory toNow we can set up our factory to
hold our resource and pass it tohold our resource and pass it to
our controller and our templateour controller and our template
// app/assets/factories/todoFactory.js
Todo.factory("Todo", function($resource){
return $resource("/api/todos/:id", { id: "@id" });
});
// app/assets/controllers/todoCtrl.js
Todo.controller("TodoCtrl", function($scope, Todo){
$scope.todos = Todo.query();
$scope.addTodo = function() {
$scope.data = new Todo();
$scope.data.name = $scope.newTodo.trim();
Todo.save($scope.data, function(){
$scope.todos = Todo.query();
$scope.newTodo = '';
})
}
});
// app/assets/templates/index.html
<p>Hello RailsConf!</p>
<ul>
<li ng-repeat="t in todos">
{{t.name}}
</li>
</ul>
<form ng-submit="addTodo()">
<input placeholder="I need to..." ng-model="newTodo" autofocus>
</form>
RecapRecap
1. Data binding in Angular is powerfulData binding in Angular is powerful
2. ngResource makes requests easyngResource makes requests easy
3. Multiple API calls to initialize application canMultiple API calls to initialize application can
get trickyget tricky
Ember! Yeah!Ember! Yeah!
Created by Tom Dale andCreated by Tom Dale and
Yehuda KatzYehuda Katz
Made for large, ambitiousMade for large, ambitious
applicationsapplications
Favors convention overFavors convention over
configurationconfiguration
Ember Data is absolutelyEmber Data is absolutely
wonderfulwonderful
Ember-CLIEmber-CLI
The new standard for developing Ember apps
Integrates with Rails via the ember-cli-rails gem
What we'll beWhat we'll be
working withworking with
class User < ActiveRecord::Base
has_many :todos
end
class Todo < ActiveRecord::Base
belongs_to :user
end
class EmberController < ApplicationController
def preload
@todos = current_user.todos
end
end
Rails.application.routes.draw do
root 'ember#preload'
end
# Gemfile
gem "active_model_serializers"
gem "ember-cli-rails"
$ rails g serializer todo
create app/serializers/todo_serializer.rb
class TodoSerializer < ActiveModel::Serializer
embed :ids, include: true
attributes :id, :name
end
{
"todos": [
{
"id": 1,
"name": "Milk"
},
{
"id": 2,
"name": "Coffee"
},
{
"id": 3,
"name": "Cupcakes"
}
]
}
Create a new serializer, set it up to workCreate a new serializer, set it up to work
with Emberwith Ember
Now that we're all set up, whatNow that we're all set up, what
are we trying to accomplish?are we trying to accomplish?
Instead of using JSON calls, weInstead of using JSON calls, we
want to preload Emberwant to preload Ember
Why?Why?
Minimize round trips to the serverMinimize round trips to the server
Bootstrapping the app means a quickerBootstrapping the app means a quicker
experience for our usersexperience for our users
# app/controllers/ember_controller.rb
class EmberController < ApplicationController
def preload
@todos = current_user.todos
preload! @todos, serializer: TodoSerializer
end
def preload!(data, opts = {})
@preload ||= []
data = prepare_data(data, opts)
@preload << data unless data.nil?
end
def prepare_data(data, opts = {})
data = data.to_a if data.respond_to? :to_ary
data = [data] unless data.is_a? Array
return if data.empty?
options[:root] ||= data.first.class.to_s.underscore.pluralize
options[:each_serializer] = options[:serializer] if options[:serializer]
ActiveModel::ArraySerializer.new(data, options)
end
end
We'll pass this to Ember via theWe'll pass this to Ember via the
window.window.
# app/views/layouts/application.html.haml
= stylesheet_link_tag :frontend
:javascript
window.preloadEmberData = #{(@preload || []).to_json};
= include_ember_script_tags :frontend
%body
= yield
github.com/hummingbird-me/hummingbird
Let's get setup withLet's get setup with
our client-side codeour client-side code
$ rails g ember-cli:init
create config/initializers/ember.rb
# config/initializer/ember.rb
EmberCLI.configure do |config|
config.app :frontend, path: Rails.root.join('frontend').to_s
end
$ ember new frontend --skip-git
version: 0.2.3
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
...
$ ember g resource todos
version: 0.2.3
installing
create app/models/todo.js
installing
create tests/unit/models/todo-test.js
installing
create app/routes/todos.js
create app/templates/todos.hbs
installing
create tests/unit/routes/todos-test.js
$ ember g adapter application
version: 0.2.3
installing
create app/adapters/application.js
installing
create tests/unit/adapters/application-test.js
$ ember g serializer application
version: 0.2.3
installing
create app/serializers/application.js
installing
create tests/unit/serializers/application-test.js
// frontend/app/models/todo.js
import DS from 'ember-data';
var Todo = DS.Model.extend({
name: DS.attr('string')
});
export default Todo;
// frontend/app/adapters/application.js
import DS from 'ember-data';
export default DS.ActiveModelAdapter.extend({
});
// frontend/app/initializers/preload.js
export function initialize(container) {
if (window.preloadEmberData) {
var store = container.lookup('store:main');
window.preloadEmberData.forEach(function(item) {
store.pushPayload(item);
});
}
}
export default {
name: 'preload',
after: 'store',
initialize: initialize
};
Ember will initializeEmber will initialize
Ember Data objectsEmber Data objects
for us, inferring thefor us, inferring the
correct type from thecorrect type from the
root of the JSONroot of the JSON
responseresponse
Now we can use our route to find the data
and render it via a template
// frontend/app/router.js
export default Router.map(function() {
this.resource('todos', { path: '/' }, function() {});
});
// frontend/app/routes/todos/index.js
export default Ember.Route.extend({
model: function() {
return this.store.all('todo')
}
});
// frontend/app/templates/todos/index.hbs
<h2>Todo:</h2>
<ul>
{{#each todo in model}}
<li>{{todo.name}}</li>
{{/each}}
</ul>
RecapRecap
1. Don't fight Ember. Use conventionsDon't fight Ember. Use conventions
like AMSlike AMS
2. Preloading is extremely powerfulPreloading is extremely powerful
3. Avoiding spinners and loading screens
means a great experience
So let's talkSo let's talk
about React.about React.
Developed by Facebook
One-way data binding
Virtual DOM
Isomorphic Javascript
No initial API call, noNo initial API call, no
preloading, renderpreloading, render
straight from thestraight from the
server.server.
http://bensmithett.com/server-rendered-react-components-in-rails/
# app/controllers/todos_controller.rb
class TodosController < ApplicationController
def index
@load = {
:todos => current_user.todos,
:form => {
:action => todos_path,
:csrf_param => request_forgery_protection_token,
:csrf_token => form_authenticity_token
}
}
end
def create
@todo = Todo.create(todo_params)
render json: @todo
end
def todo_params
params.require(:todo).permit(:name)
end
end
Use the react-rails gemUse the react-rails gem
# Gemfile
gem "react-rails"
$ rails g react:install
# app/views/todos/index.html.erb
<%= react_component('Todos',
{:load => @load.to_json},
{:prerender => true}) %>
Really nice viewReally nice view
helpershelpers
The magic lives in {:prerender => true}
React is builtReact is built
around componentsaround components
Each component should have one isolated
responsibility.
# app/assets/javascripts/components/_todos.js.jsx
var Todos = React.createClass({
getInitialState: function () {
return JSON.parse(this.props.load);
},
newTodo: function ( formData, action ) {
$.ajax({
data: formData,
url: action,
type: "POST",
dataType: "json",
success: function (data) {
this.setState({todos: this.state.todos.concat([data]});
}.bind(this)
});
},
render: function () {
return (
<div>
<ul>
<TodosList todos={this.state.todos} />
</ul>
<TodoForm form={this.state.form} onNewTodo={this.newTodo} />
</div>
);
}
});
TodosList ComponentTodosList Component
// app/assets/javascripts/components/_todos_list.js.jsx
var TodosList = React.createClass({
render: function () {
var allTodos = this.props.todos.map(function (todo) {
return <Todo name={todo.name} />
});
return (
<div>
{ allTodos }
</div>
)
}
});
// app/assets/javascripts/components/_todo.js.jsx
var Todo = React.createClass({
render: function (){
return (
<div>
<li>{this.props.name}</li>
</div>
)
}
});
And now the form...And now the form...
// app/assets/javascripts/components/_todo_form.js.jsx
var TodoForm = React.createClass({
handleSubmit: function (e) {
e.preventDefault();
var formData = $(this.refs.form.getDOMNode()).serialize();
this.props.onNewTodo(formData, this.props.form.action);
this.refs.name.getDOMNode().value = "";
},
render: function () {
return (
<form ref="form"action={this.props.form.action} method="post" onSubmit={this.handleSubmit}>
<input type="hidden" name={this.props.form.csrf_param } value={this.props.form.csrf_token}/>
<input ref="name" name="todo[name]" placeholder="I need to do..." />
<button type="submit">New Todo</button>
</form>
)
}
});
RecapRecap
1. Each component should have only oneEach component should have only one
responsibilityresponsibility
2. Prerender on the server for SEO, usability andPrerender on the server for SEO, usability and
other benefitsother benefits
3. UJS will mount your component and take careUJS will mount your component and take care
of the handoffof the handoff
IsomorphicIsomorphic
Javascript is theJavascript is the
future.future.
React
Ember 2.0 with FastBoot
Angular 2?
Where we've come from andWhere we've come from and
where we are goingwhere we are going
1. Constructing API's that serve JSON to the clientConstructing API's that serve JSON to the client
2. Preload your data on startup to avoid spinners andPreload your data on startup to avoid spinners and
loading screensloading screens
3. Server-side rendering for SEO, startup time and a greatServer-side rendering for SEO, startup time and a great
user experienceuser experience
Thanks!Thanks!
Would love to answer any questions
Please feel free to tweet at me or get in
touch in any other way.
@danielspecs
spector.io

More Related Content

What's hot

3 things you must know to think reactive - Geecon Kraków 2015
3 things you must know to think reactive - Geecon Kraków 20153 things you must know to think reactive - Geecon Kraków 2015
3 things you must know to think reactive - Geecon Kraków 2015Manuel Bernhardt
 
Testing Ruby with Rspec (a beginner's guide)
Testing Ruby with Rspec (a beginner's guide)Testing Ruby with Rspec (a beginner's guide)
Testing Ruby with Rspec (a beginner's guide)Vysakh Sreenivasan
 
Federico Feroldi - Scala microservices
Federico Feroldi - Scala microservicesFederico Feroldi - Scala microservices
Federico Feroldi - Scala microservicesScala Italy
 
Testing Ember Apps: Managing Dependency
Testing Ember Apps: Managing DependencyTesting Ember Apps: Managing Dependency
Testing Ember Apps: Managing DependencyMatthew Beale
 
Scaling up task processing with Celery
Scaling up task processing with CeleryScaling up task processing with Celery
Scaling up task processing with CeleryNicolas Grasset
 
The internet of (lego) trains
The internet of (lego) trainsThe internet of (lego) trains
The internet of (lego) trainsGrzegorz Duda
 
Intro to JavaScript
Intro to JavaScriptIntro to JavaScript
Intro to JavaScriptYakov Fain
 
Back to the futures, actors and pipes: using Akka for large-scale data migration
Back to the futures, actors and pipes: using Akka for large-scale data migrationBack to the futures, actors and pipes: using Akka for large-scale data migration
Back to the futures, actors and pipes: using Akka for large-scale data migrationManuel Bernhardt
 
Mastering the Sling Rewriter
Mastering the Sling RewriterMastering the Sling Rewriter
Mastering the Sling RewriterJustin Edelson
 
Asynchronous Task Queues with Celery
Asynchronous Task Queues with CeleryAsynchronous Task Queues with Celery
Asynchronous Task Queues with CeleryKishor Kumar
 
Method and decorator
Method and decoratorMethod and decorator
Method and decoratorCeline George
 
【AWS Developers Meetup】RESTful APIをChaliceで紐解く
【AWS Developers Meetup】RESTful APIをChaliceで紐解く【AWS Developers Meetup】RESTful APIをChaliceで紐解く
【AWS Developers Meetup】RESTful APIをChaliceで紐解くAmazon Web Services Japan
 
RSpec 3: The new, the old, the good
RSpec 3: The new, the old, the goodRSpec 3: The new, the old, the good
RSpec 3: The new, the old, the goodmglrnm
 
Symfony 4 Workshop - Limenius
Symfony 4 Workshop - LimeniusSymfony 4 Workshop - Limenius
Symfony 4 Workshop - LimeniusIgnacio Martín
 
Automated testing with RSpec
Automated testing with RSpecAutomated testing with RSpec
Automated testing with RSpecNascenia IT
 

What's hot (20)

3 things you must know to think reactive - Geecon Kraków 2015
3 things you must know to think reactive - Geecon Kraków 20153 things you must know to think reactive - Geecon Kraków 2015
3 things you must know to think reactive - Geecon Kraków 2015
 
Testing Ruby with Rspec (a beginner's guide)
Testing Ruby with Rspec (a beginner's guide)Testing Ruby with Rspec (a beginner's guide)
Testing Ruby with Rspec (a beginner's guide)
 
Federico Feroldi - Scala microservices
Federico Feroldi - Scala microservicesFederico Feroldi - Scala microservices
Federico Feroldi - Scala microservices
 
Mist - Serverless proxy to Apache Spark
Mist - Serverless proxy to Apache SparkMist - Serverless proxy to Apache Spark
Mist - Serverless proxy to Apache Spark
 
Testing Ember Apps: Managing Dependency
Testing Ember Apps: Managing DependencyTesting Ember Apps: Managing Dependency
Testing Ember Apps: Managing Dependency
 
Scaling up task processing with Celery
Scaling up task processing with CeleryScaling up task processing with Celery
Scaling up task processing with Celery
 
The internet of (lego) trains
The internet of (lego) trainsThe internet of (lego) trains
The internet of (lego) trains
 
Factory Girl
Factory GirlFactory Girl
Factory Girl
 
Introduction to es6
Introduction to es6Introduction to es6
Introduction to es6
 
Intro to JavaScript
Intro to JavaScriptIntro to JavaScript
Intro to JavaScript
 
Back to the futures, actors and pipes: using Akka for large-scale data migration
Back to the futures, actors and pipes: using Akka for large-scale data migrationBack to the futures, actors and pipes: using Akka for large-scale data migration
Back to the futures, actors and pipes: using Akka for large-scale data migration
 
Mastering the Sling Rewriter
Mastering the Sling RewriterMastering the Sling Rewriter
Mastering the Sling Rewriter
 
Advance JS and oop
Advance JS and oopAdvance JS and oop
Advance JS and oop
 
Asynchronous Task Queues with Celery
Asynchronous Task Queues with CeleryAsynchronous Task Queues with Celery
Asynchronous Task Queues with Celery
 
Method and decorator
Method and decoratorMethod and decorator
Method and decorator
 
【AWS Developers Meetup】RESTful APIをChaliceで紐解く
【AWS Developers Meetup】RESTful APIをChaliceで紐解く【AWS Developers Meetup】RESTful APIをChaliceで紐解く
【AWS Developers Meetup】RESTful APIをChaliceで紐解く
 
slingmodels
slingmodelsslingmodels
slingmodels
 
RSpec 3: The new, the old, the good
RSpec 3: The new, the old, the goodRSpec 3: The new, the old, the good
RSpec 3: The new, the old, the good
 
Symfony 4 Workshop - Limenius
Symfony 4 Workshop - LimeniusSymfony 4 Workshop - Limenius
Symfony 4 Workshop - Limenius
 
Automated testing with RSpec
Automated testing with RSpecAutomated testing with RSpec
Automated testing with RSpec
 

Similar to Crossing the Bridge: Connecting Rails and your Front-end Framework

Phoenix for Rails Devs
Phoenix for Rails DevsPhoenix for Rails Devs
Phoenix for Rails DevsDiacode
 
Connecting the Worlds of Java and Ruby with JRuby
Connecting the Worlds of Java and Ruby with JRubyConnecting the Worlds of Java and Ruby with JRuby
Connecting the Worlds of Java and Ruby with JRubyNick Sieger
 
JRuby + Rails = Awesome Java Web Framework at Jfokus 2011
JRuby + Rails = Awesome Java Web Framework at Jfokus 2011JRuby + Rails = Awesome Java Web Framework at Jfokus 2011
JRuby + Rails = Awesome Java Web Framework at Jfokus 2011Nick Sieger
 
Rapid Prototyping FTW!!!
Rapid Prototyping FTW!!!Rapid Prototyping FTW!!!
Rapid Prototyping FTW!!!cloudbring
 
Single Page Web Applications with CoffeeScript, Backbone and Jasmine
Single Page Web Applications with CoffeeScript, Backbone and JasmineSingle Page Web Applications with CoffeeScript, Backbone and Jasmine
Single Page Web Applications with CoffeeScript, Backbone and JasminePaulo Ragonha
 
AWS re:Invent 2016: Chalice: A Serverless Microframework for Python (DEV308)
AWS re:Invent 2016: Chalice: A Serverless Microframework for Python (DEV308)AWS re:Invent 2016: Chalice: A Serverless Microframework for Python (DEV308)
AWS re:Invent 2016: Chalice: A Serverless Microframework for Python (DEV308)Amazon Web Services
 
RubyEnRails2007 - Dr Nic Williams - Keynote
RubyEnRails2007 - Dr Nic Williams - KeynoteRubyEnRails2007 - Dr Nic Williams - Keynote
RubyEnRails2007 - Dr Nic Williams - KeynoteDr Nic Williams
 
Building Cloud Castles
Building Cloud CastlesBuilding Cloud Castles
Building Cloud CastlesBen Scofield
 
Tasks: you gotta know how to run them
Tasks: you gotta know how to run themTasks: you gotta know how to run them
Tasks: you gotta know how to run themFilipe Ximenes
 
Ruby on Rails survival guide of an aged Java developer
Ruby on Rails survival guide of an aged Java developerRuby on Rails survival guide of an aged Java developer
Ruby on Rails survival guide of an aged Java developergicappa
 
TorqueBox - Ruby Hoedown 2011
TorqueBox - Ruby Hoedown 2011TorqueBox - Ruby Hoedown 2011
TorqueBox - Ruby Hoedown 2011Lance Ball
 
Building web framework with Rack
Building web framework with RackBuilding web framework with Rack
Building web framework with Racksickill
 
Using Sinatra to Build REST APIs in Ruby
Using Sinatra to Build REST APIs in RubyUsing Sinatra to Build REST APIs in Ruby
Using Sinatra to Build REST APIs in RubyLaunchAny
 

Similar to Crossing the Bridge: Connecting Rails and your Front-end Framework (20)

Phoenix for Rails Devs
Phoenix for Rails DevsPhoenix for Rails Devs
Phoenix for Rails Devs
 
Connecting the Worlds of Java and Ruby with JRuby
Connecting the Worlds of Java and Ruby with JRubyConnecting the Worlds of Java and Ruby with JRuby
Connecting the Worlds of Java and Ruby with JRuby
 
Intro to Rack
Intro to RackIntro to Rack
Intro to Rack
 
JRuby + Rails = Awesome Java Web Framework at Jfokus 2011
JRuby + Rails = Awesome Java Web Framework at Jfokus 2011JRuby + Rails = Awesome Java Web Framework at Jfokus 2011
JRuby + Rails = Awesome Java Web Framework at Jfokus 2011
 
Rapid Prototyping FTW!!!
Rapid Prototyping FTW!!!Rapid Prototyping FTW!!!
Rapid Prototyping FTW!!!
 
Single Page Web Applications with CoffeeScript, Backbone and Jasmine
Single Page Web Applications with CoffeeScript, Backbone and JasmineSingle Page Web Applications with CoffeeScript, Backbone and Jasmine
Single Page Web Applications with CoffeeScript, Backbone and Jasmine
 
AWS re:Invent 2016: Chalice: A Serverless Microframework for Python (DEV308)
AWS re:Invent 2016: Chalice: A Serverless Microframework for Python (DEV308)AWS re:Invent 2016: Chalice: A Serverless Microframework for Python (DEV308)
AWS re:Invent 2016: Chalice: A Serverless Microframework for Python (DEV308)
 
RubyEnRails2007 - Dr Nic Williams - Keynote
RubyEnRails2007 - Dr Nic Williams - KeynoteRubyEnRails2007 - Dr Nic Williams - Keynote
RubyEnRails2007 - Dr Nic Williams - Keynote
 
Building Cloud Castles
Building Cloud CastlesBuilding Cloud Castles
Building Cloud Castles
 
Elixir on Containers
Elixir on ContainersElixir on Containers
Elixir on Containers
 
Supa fast Ruby + Rails
Supa fast Ruby + RailsSupa fast Ruby + Rails
Supa fast Ruby + Rails
 
Having Fun with Play
Having Fun with PlayHaving Fun with Play
Having Fun with Play
 
Wider than rails
Wider than railsWider than rails
Wider than rails
 
Tasks: you gotta know how to run them
Tasks: you gotta know how to run themTasks: you gotta know how to run them
Tasks: you gotta know how to run them
 
Ruby on Rails survival guide of an aged Java developer
Ruby on Rails survival guide of an aged Java developerRuby on Rails survival guide of an aged Java developer
Ruby on Rails survival guide of an aged Java developer
 
Play vs Rails
Play vs RailsPlay vs Rails
Play vs Rails
 
TorqueBox - Ruby Hoedown 2011
TorqueBox - Ruby Hoedown 2011TorqueBox - Ruby Hoedown 2011
TorqueBox - Ruby Hoedown 2011
 
Building web framework with Rack
Building web framework with RackBuilding web framework with Rack
Building web framework with Rack
 
Using Sinatra to Build REST APIs in Ruby
Using Sinatra to Build REST APIs in RubyUsing Sinatra to Build REST APIs in Ruby
Using Sinatra to Build REST APIs in Ruby
 
Practical Celery
Practical CeleryPractical Celery
Practical Celery
 

Recently uploaded

Innovate and Collaborate- Harnessing the Power of Open Source Software.pdf
Innovate and Collaborate- Harnessing the Power of Open Source Software.pdfInnovate and Collaborate- Harnessing the Power of Open Source Software.pdf
Innovate and Collaborate- Harnessing the Power of Open Source Software.pdfYashikaSharma391629
 
20240415 [Container Plumbing Days] Usernetes Gen2 - Kubernetes in Rootless Do...
20240415 [Container Plumbing Days] Usernetes Gen2 - Kubernetes in Rootless Do...20240415 [Container Plumbing Days] Usernetes Gen2 - Kubernetes in Rootless Do...
20240415 [Container Plumbing Days] Usernetes Gen2 - Kubernetes in Rootless Do...Akihiro Suda
 
React Server Component in Next.js by Hanief Utama
React Server Component in Next.js by Hanief UtamaReact Server Component in Next.js by Hanief Utama
React Server Component in Next.js by Hanief UtamaHanief Utama
 
英国UN学位证,北安普顿大学毕业证书1:1制作
英国UN学位证,北安普顿大学毕业证书1:1制作英国UN学位证,北安普顿大学毕业证书1:1制作
英国UN学位证,北安普顿大学毕业证书1:1制作qr0udbr0
 
Intelligent Home Wi-Fi Solutions | ThinkPalm
Intelligent Home Wi-Fi Solutions | ThinkPalmIntelligent Home Wi-Fi Solutions | ThinkPalm
Intelligent Home Wi-Fi Solutions | ThinkPalmSujith Sukumaran
 
Global Identity Enrolment and Verification Pro Solution - Cizo Technology Ser...
Global Identity Enrolment and Verification Pro Solution - Cizo Technology Ser...Global Identity Enrolment and Verification Pro Solution - Cizo Technology Ser...
Global Identity Enrolment and Verification Pro Solution - Cizo Technology Ser...Cizo Technology Services
 
How To Manage Restaurant Staff -BTRESTRO
How To Manage Restaurant Staff -BTRESTROHow To Manage Restaurant Staff -BTRESTRO
How To Manage Restaurant Staff -BTRESTROmotivationalword821
 
Precise and Complete Requirements? An Elusive Goal
Precise and Complete Requirements? An Elusive GoalPrecise and Complete Requirements? An Elusive Goal
Precise and Complete Requirements? An Elusive GoalLionel Briand
 
Unveiling the Future: Sylius 2.0 New Features
Unveiling the Future: Sylius 2.0 New FeaturesUnveiling the Future: Sylius 2.0 New Features
Unveiling the Future: Sylius 2.0 New FeaturesŁukasz Chruściel
 
MYjobs Presentation Django-based project
MYjobs Presentation Django-based projectMYjobs Presentation Django-based project
MYjobs Presentation Django-based projectAnoyGreter
 
Alfresco TTL#157 - Troubleshooting Made Easy: Deciphering Alfresco mTLS Confi...
Alfresco TTL#157 - Troubleshooting Made Easy: Deciphering Alfresco mTLS Confi...Alfresco TTL#157 - Troubleshooting Made Easy: Deciphering Alfresco mTLS Confi...
Alfresco TTL#157 - Troubleshooting Made Easy: Deciphering Alfresco mTLS Confi...Angel Borroy López
 
Software Project Health Check: Best Practices and Techniques for Your Product...
Software Project Health Check: Best Practices and Techniques for Your Product...Software Project Health Check: Best Practices and Techniques for Your Product...
Software Project Health Check: Best Practices and Techniques for Your Product...Velvetech LLC
 
SensoDat: Simulation-based Sensor Dataset of Self-driving Cars
SensoDat: Simulation-based Sensor Dataset of Self-driving CarsSensoDat: Simulation-based Sensor Dataset of Self-driving Cars
SensoDat: Simulation-based Sensor Dataset of Self-driving CarsChristian Birchler
 
Balasore Best It Company|| Top 10 IT Company || Balasore Software company Odisha
Balasore Best It Company|| Top 10 IT Company || Balasore Software company OdishaBalasore Best It Company|| Top 10 IT Company || Balasore Software company Odisha
Balasore Best It Company|| Top 10 IT Company || Balasore Software company Odishasmiwainfosol
 
Implementing Zero Trust strategy with Azure
Implementing Zero Trust strategy with AzureImplementing Zero Trust strategy with Azure
Implementing Zero Trust strategy with AzureDinusha Kumarasiri
 
PREDICTING RIVER WATER QUALITY ppt presentation
PREDICTING  RIVER  WATER QUALITY  ppt presentationPREDICTING  RIVER  WATER QUALITY  ppt presentation
PREDICTING RIVER WATER QUALITY ppt presentationvaddepallysandeep122
 
Xen Safety Embedded OSS Summit April 2024 v4.pdf
Xen Safety Embedded OSS Summit April 2024 v4.pdfXen Safety Embedded OSS Summit April 2024 v4.pdf
Xen Safety Embedded OSS Summit April 2024 v4.pdfStefano Stabellini
 
Powering Real-Time Decisions with Continuous Data Streams
Powering Real-Time Decisions with Continuous Data StreamsPowering Real-Time Decisions with Continuous Data Streams
Powering Real-Time Decisions with Continuous Data StreamsSafe Software
 
GOING AOT WITH GRAALVM – DEVOXX GREECE.pdf
GOING AOT WITH GRAALVM – DEVOXX GREECE.pdfGOING AOT WITH GRAALVM – DEVOXX GREECE.pdf
GOING AOT WITH GRAALVM – DEVOXX GREECE.pdfAlina Yurenko
 
Post Quantum Cryptography – The Impact on Identity
Post Quantum Cryptography – The Impact on IdentityPost Quantum Cryptography – The Impact on Identity
Post Quantum Cryptography – The Impact on Identityteam-WIBU
 

Recently uploaded (20)

Innovate and Collaborate- Harnessing the Power of Open Source Software.pdf
Innovate and Collaborate- Harnessing the Power of Open Source Software.pdfInnovate and Collaborate- Harnessing the Power of Open Source Software.pdf
Innovate and Collaborate- Harnessing the Power of Open Source Software.pdf
 
20240415 [Container Plumbing Days] Usernetes Gen2 - Kubernetes in Rootless Do...
20240415 [Container Plumbing Days] Usernetes Gen2 - Kubernetes in Rootless Do...20240415 [Container Plumbing Days] Usernetes Gen2 - Kubernetes in Rootless Do...
20240415 [Container Plumbing Days] Usernetes Gen2 - Kubernetes in Rootless Do...
 
React Server Component in Next.js by Hanief Utama
React Server Component in Next.js by Hanief UtamaReact Server Component in Next.js by Hanief Utama
React Server Component in Next.js by Hanief Utama
 
英国UN学位证,北安普顿大学毕业证书1:1制作
英国UN学位证,北安普顿大学毕业证书1:1制作英国UN学位证,北安普顿大学毕业证书1:1制作
英国UN学位证,北安普顿大学毕业证书1:1制作
 
Intelligent Home Wi-Fi Solutions | ThinkPalm
Intelligent Home Wi-Fi Solutions | ThinkPalmIntelligent Home Wi-Fi Solutions | ThinkPalm
Intelligent Home Wi-Fi Solutions | ThinkPalm
 
Global Identity Enrolment and Verification Pro Solution - Cizo Technology Ser...
Global Identity Enrolment and Verification Pro Solution - Cizo Technology Ser...Global Identity Enrolment and Verification Pro Solution - Cizo Technology Ser...
Global Identity Enrolment and Verification Pro Solution - Cizo Technology Ser...
 
How To Manage Restaurant Staff -BTRESTRO
How To Manage Restaurant Staff -BTRESTROHow To Manage Restaurant Staff -BTRESTRO
How To Manage Restaurant Staff -BTRESTRO
 
Precise and Complete Requirements? An Elusive Goal
Precise and Complete Requirements? An Elusive GoalPrecise and Complete Requirements? An Elusive Goal
Precise and Complete Requirements? An Elusive Goal
 
Unveiling the Future: Sylius 2.0 New Features
Unveiling the Future: Sylius 2.0 New FeaturesUnveiling the Future: Sylius 2.0 New Features
Unveiling the Future: Sylius 2.0 New Features
 
MYjobs Presentation Django-based project
MYjobs Presentation Django-based projectMYjobs Presentation Django-based project
MYjobs Presentation Django-based project
 
Alfresco TTL#157 - Troubleshooting Made Easy: Deciphering Alfresco mTLS Confi...
Alfresco TTL#157 - Troubleshooting Made Easy: Deciphering Alfresco mTLS Confi...Alfresco TTL#157 - Troubleshooting Made Easy: Deciphering Alfresco mTLS Confi...
Alfresco TTL#157 - Troubleshooting Made Easy: Deciphering Alfresco mTLS Confi...
 
Software Project Health Check: Best Practices and Techniques for Your Product...
Software Project Health Check: Best Practices and Techniques for Your Product...Software Project Health Check: Best Practices and Techniques for Your Product...
Software Project Health Check: Best Practices and Techniques for Your Product...
 
SensoDat: Simulation-based Sensor Dataset of Self-driving Cars
SensoDat: Simulation-based Sensor Dataset of Self-driving CarsSensoDat: Simulation-based Sensor Dataset of Self-driving Cars
SensoDat: Simulation-based Sensor Dataset of Self-driving Cars
 
Balasore Best It Company|| Top 10 IT Company || Balasore Software company Odisha
Balasore Best It Company|| Top 10 IT Company || Balasore Software company OdishaBalasore Best It Company|| Top 10 IT Company || Balasore Software company Odisha
Balasore Best It Company|| Top 10 IT Company || Balasore Software company Odisha
 
Implementing Zero Trust strategy with Azure
Implementing Zero Trust strategy with AzureImplementing Zero Trust strategy with Azure
Implementing Zero Trust strategy with Azure
 
PREDICTING RIVER WATER QUALITY ppt presentation
PREDICTING  RIVER  WATER QUALITY  ppt presentationPREDICTING  RIVER  WATER QUALITY  ppt presentation
PREDICTING RIVER WATER QUALITY ppt presentation
 
Xen Safety Embedded OSS Summit April 2024 v4.pdf
Xen Safety Embedded OSS Summit April 2024 v4.pdfXen Safety Embedded OSS Summit April 2024 v4.pdf
Xen Safety Embedded OSS Summit April 2024 v4.pdf
 
Powering Real-Time Decisions with Continuous Data Streams
Powering Real-Time Decisions with Continuous Data StreamsPowering Real-Time Decisions with Continuous Data Streams
Powering Real-Time Decisions with Continuous Data Streams
 
GOING AOT WITH GRAALVM – DEVOXX GREECE.pdf
GOING AOT WITH GRAALVM – DEVOXX GREECE.pdfGOING AOT WITH GRAALVM – DEVOXX GREECE.pdf
GOING AOT WITH GRAALVM – DEVOXX GREECE.pdf
 
Post Quantum Cryptography – The Impact on Identity
Post Quantum Cryptography – The Impact on IdentityPost Quantum Cryptography – The Impact on Identity
Post Quantum Cryptography – The Impact on Identity
 

Crossing the Bridge: Connecting Rails and your Front-end Framework

  • 1. Crossing the Bridge:Crossing the Bridge: Connecting Rails and your Front-endConnecting Rails and your Front-end FrameworkFramework @danielspecs@danielspecs
  • 2. This is what we're trying to avoidThis is what we're trying to avoid
  • 3. Instead we want thisInstead we want this
  • 4. A GameplanA Gameplan Understand the tradeoffs you'll make Deeply integrate your framework with Rails Share data in a consistent and maintainable way
  • 5. Daniel SpectorDaniel Spector Software Engineer at Lifebooker @danielspecs spector.io Flatiron School Rails/Javascript/Swift/Clojure
  • 6. What are youWhat are you getting yourselfgetting yourself into?into?
  • 7. Javascript. Wat.Javascript. Wat. > [] + {} => [object Object] > {} + [] => 0
  • 8. Courtesy of Alex Matchneer
  • 9. Always thinkAlways think about theabout the bigger picturebigger picture You will encounter a lot ofYou will encounter a lot of tradeoffs.tradeoffs.
  • 10. Some of the fun thatSome of the fun that awaits...awaits... Duplicated modelsDuplicated models Separate codebasesSeparate codebases ComplexityComplexity
  • 13. What do people want?What do people want? Maintainable,Maintainable, sustainable,sustainable, performantperformant applicationsapplications
  • 14. But now that you'veBut now that you've been warned...been warned...
  • 15. Holy s**t canHoly s**t can you make someyou make some awesomeawesome applications.applications.
  • 16. RecapRecap Never lose sight of the ultimate goalNever lose sight of the ultimate goal Understand the tradeoffs that willUnderstand the tradeoffs that will comecome There may be a solutionThere may be a solution
  • 17. Now, let's dive inNow, let's dive in
  • 18. What we're going to be building:What we're going to be building: TodoMVC on RailsTodoMVC on Rails Scaffolding out the same application in each ofScaffolding out the same application in each of the frameworks makes it easy to referencethe frameworks makes it easy to reference
  • 20. Now let's have a lookNow let's have a look at Angularat Angular
  • 21. Developed by GoogleDeveloped by Google Two-way data bindingTwo-way data binding Dependency InjectionDependency Injection But... Angular 2But... Angular 2
  • 22. First, let's get ourFirst, let's get our Rails project API readyRails project API ready
  • 23. # app/controllers/api/todos_controller.rb class Api::TodosController < ApplicationController respond_to :json def index @todos = Todo.all render json: @todos end def create @todo = Todo.create(todo_params) render json: @todo end private def todo_params params.require(:todo).permit(:item) end end # config/routes.rb namespace :api, :defaults => {:format => :json} do resources :todos, only: [:index, :create] end # app/models/todo.rb class Todo < ActiveRecord::Base end
  • 24. There's no official AngularThere's no official Angular integration with Rails...integration with Rails... So that's a perfect opportunity toSo that's a perfect opportunity to try out Bower.try out Bower.
  • 25. Created by Twitter One centralized location for packages Can be integrated with Rails via the bower-rails gem
  • 26. $ npm install -g bower # Gemfile gem "bower-rails", "~> 0.9.2" $ rails g bower_rails:initialize # Bowerfile # Puts to ./vendor/assets/bower_components asset "angular" asset "angular-resource" asset "angular-route"
  • 27. How can we manageHow can we manage our client-side dataour client-side data to make it easy toto make it easy to work with?work with?
  • 28. ngResource is an optional libraryngResource is an optional library to map basic CRUD actions toto map basic CRUD actions to specific method calls.specific method calls. Let's scaffold out a basicLet's scaffold out a basic Angular and see how we canAngular and see how we can integrate ngResourceintegrate ngResource
  • 29. // app/assets/main.js // This is the main entry point for our application. var Todo = angular .module('todo', ['ngResource', 'ngRoute']) .config(['$routeProvider', '$httpProvider', function($routeProvider, $httpProvider) { // We need to add this for Rails CSRF token protection $httpProvider.defaults.headers.common['X-CSRF-Token'] = $('meta[name=csrf-token]').attr('content'); // Right now we have one route but we could have as many as we want $routeProvider .when("/", {templateUrl: "../assets/index.html", controller: "TodoCtrl"}) }]); # config/application.rb config.assets.paths << "#{Rails.root}/app/assets/templates"
  • 30. Now we can set up our factory toNow we can set up our factory to hold our resource and pass it tohold our resource and pass it to our controller and our templateour controller and our template
  • 31. // app/assets/factories/todoFactory.js Todo.factory("Todo", function($resource){ return $resource("/api/todos/:id", { id: "@id" }); }); // app/assets/controllers/todoCtrl.js Todo.controller("TodoCtrl", function($scope, Todo){ $scope.todos = Todo.query(); $scope.addTodo = function() { $scope.data = new Todo(); $scope.data.name = $scope.newTodo.trim(); Todo.save($scope.data, function(){ $scope.todos = Todo.query(); $scope.newTodo = ''; }) } });
  • 32. // app/assets/templates/index.html <p>Hello RailsConf!</p> <ul> <li ng-repeat="t in todos"> {{t.name}} </li> </ul> <form ng-submit="addTodo()"> <input placeholder="I need to..." ng-model="newTodo" autofocus> </form>
  • 33. RecapRecap 1. Data binding in Angular is powerfulData binding in Angular is powerful 2. ngResource makes requests easyngResource makes requests easy 3. Multiple API calls to initialize application canMultiple API calls to initialize application can get trickyget tricky
  • 35. Created by Tom Dale andCreated by Tom Dale and Yehuda KatzYehuda Katz Made for large, ambitiousMade for large, ambitious applicationsapplications Favors convention overFavors convention over configurationconfiguration Ember Data is absolutelyEmber Data is absolutely wonderfulwonderful
  • 36. Ember-CLIEmber-CLI The new standard for developing Ember apps Integrates with Rails via the ember-cli-rails gem
  • 37. What we'll beWhat we'll be working withworking with class User < ActiveRecord::Base has_many :todos end class Todo < ActiveRecord::Base belongs_to :user end class EmberController < ApplicationController def preload @todos = current_user.todos end end Rails.application.routes.draw do root 'ember#preload' end
  • 39. $ rails g serializer todo create app/serializers/todo_serializer.rb class TodoSerializer < ActiveModel::Serializer embed :ids, include: true attributes :id, :name end { "todos": [ { "id": 1, "name": "Milk" }, { "id": 2, "name": "Coffee" }, { "id": 3, "name": "Cupcakes" } ] } Create a new serializer, set it up to workCreate a new serializer, set it up to work with Emberwith Ember
  • 40. Now that we're all set up, whatNow that we're all set up, what are we trying to accomplish?are we trying to accomplish? Instead of using JSON calls, weInstead of using JSON calls, we want to preload Emberwant to preload Ember
  • 41. Why?Why? Minimize round trips to the serverMinimize round trips to the server Bootstrapping the app means a quickerBootstrapping the app means a quicker experience for our usersexperience for our users
  • 42. # app/controllers/ember_controller.rb class EmberController < ApplicationController def preload @todos = current_user.todos preload! @todos, serializer: TodoSerializer end def preload!(data, opts = {}) @preload ||= [] data = prepare_data(data, opts) @preload << data unless data.nil? end def prepare_data(data, opts = {}) data = data.to_a if data.respond_to? :to_ary data = [data] unless data.is_a? Array return if data.empty? options[:root] ||= data.first.class.to_s.underscore.pluralize options[:each_serializer] = options[:serializer] if options[:serializer] ActiveModel::ArraySerializer.new(data, options) end end
  • 43. We'll pass this to Ember via theWe'll pass this to Ember via the window.window. # app/views/layouts/application.html.haml = stylesheet_link_tag :frontend :javascript window.preloadEmberData = #{(@preload || []).to_json}; = include_ember_script_tags :frontend %body = yield github.com/hummingbird-me/hummingbird
  • 44. Let's get setup withLet's get setup with our client-side codeour client-side code
  • 45. $ rails g ember-cli:init create config/initializers/ember.rb # config/initializer/ember.rb EmberCLI.configure do |config| config.app :frontend, path: Rails.root.join('frontend').to_s end $ ember new frontend --skip-git version: 0.2.3 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 ...
  • 46. $ ember g resource todos version: 0.2.3 installing create app/models/todo.js installing create tests/unit/models/todo-test.js installing create app/routes/todos.js create app/templates/todos.hbs installing create tests/unit/routes/todos-test.js $ ember g adapter application version: 0.2.3 installing create app/adapters/application.js installing create tests/unit/adapters/application-test.js $ ember g serializer application version: 0.2.3 installing create app/serializers/application.js installing create tests/unit/serializers/application-test.js
  • 47. // frontend/app/models/todo.js import DS from 'ember-data'; var Todo = DS.Model.extend({ name: DS.attr('string') }); export default Todo; // frontend/app/adapters/application.js import DS from 'ember-data'; export default DS.ActiveModelAdapter.extend({ });
  • 48. // frontend/app/initializers/preload.js export function initialize(container) { if (window.preloadEmberData) { var store = container.lookup('store:main'); window.preloadEmberData.forEach(function(item) { store.pushPayload(item); }); } } export default { name: 'preload', after: 'store', initialize: initialize };
  • 49. Ember will initializeEmber will initialize Ember Data objectsEmber Data objects for us, inferring thefor us, inferring the correct type from thecorrect type from the root of the JSONroot of the JSON responseresponse
  • 50. Now we can use our route to find the data and render it via a template // frontend/app/router.js export default Router.map(function() { this.resource('todos', { path: '/' }, function() {}); }); // frontend/app/routes/todos/index.js export default Ember.Route.extend({ model: function() { return this.store.all('todo') } }); // frontend/app/templates/todos/index.hbs <h2>Todo:</h2> <ul> {{#each todo in model}} <li>{{todo.name}}</li> {{/each}} </ul>
  • 51. RecapRecap 1. Don't fight Ember. Use conventionsDon't fight Ember. Use conventions like AMSlike AMS 2. Preloading is extremely powerfulPreloading is extremely powerful 3. Avoiding spinners and loading screens means a great experience
  • 52. So let's talkSo let's talk about React.about React.
  • 53. Developed by Facebook One-way data binding Virtual DOM Isomorphic Javascript
  • 54. No initial API call, noNo initial API call, no preloading, renderpreloading, render straight from thestraight from the server.server. http://bensmithett.com/server-rendered-react-components-in-rails/
  • 55. # app/controllers/todos_controller.rb class TodosController < ApplicationController def index @load = { :todos => current_user.todos, :form => { :action => todos_path, :csrf_param => request_forgery_protection_token, :csrf_token => form_authenticity_token } } end def create @todo = Todo.create(todo_params) render json: @todo end def todo_params params.require(:todo).permit(:name) end end
  • 56. Use the react-rails gemUse the react-rails gem # Gemfile gem "react-rails" $ rails g react:install
  • 57. # app/views/todos/index.html.erb <%= react_component('Todos', {:load => @load.to_json}, {:prerender => true}) %> Really nice viewReally nice view helpershelpers The magic lives in {:prerender => true}
  • 58. React is builtReact is built around componentsaround components Each component should have one isolated responsibility.
  • 59. # app/assets/javascripts/components/_todos.js.jsx var Todos = React.createClass({ getInitialState: function () { return JSON.parse(this.props.load); }, newTodo: function ( formData, action ) { $.ajax({ data: formData, url: action, type: "POST", dataType: "json", success: function (data) { this.setState({todos: this.state.todos.concat([data]}); }.bind(this) }); }, render: function () { return ( <div> <ul> <TodosList todos={this.state.todos} /> </ul> <TodoForm form={this.state.form} onNewTodo={this.newTodo} /> </div> ); } });
  • 60. TodosList ComponentTodosList Component // app/assets/javascripts/components/_todos_list.js.jsx var TodosList = React.createClass({ render: function () { var allTodos = this.props.todos.map(function (todo) { return <Todo name={todo.name} /> }); return ( <div> { allTodos } </div> ) } }); // app/assets/javascripts/components/_todo.js.jsx var Todo = React.createClass({ render: function (){ return ( <div> <li>{this.props.name}</li> </div> ) } });
  • 61. And now the form...And now the form... // app/assets/javascripts/components/_todo_form.js.jsx var TodoForm = React.createClass({ handleSubmit: function (e) { e.preventDefault(); var formData = $(this.refs.form.getDOMNode()).serialize(); this.props.onNewTodo(formData, this.props.form.action); this.refs.name.getDOMNode().value = ""; }, render: function () { return ( <form ref="form"action={this.props.form.action} method="post" onSubmit={this.handleSubmit}> <input type="hidden" name={this.props.form.csrf_param } value={this.props.form.csrf_token}/> <input ref="name" name="todo[name]" placeholder="I need to do..." /> <button type="submit">New Todo</button> </form> ) } });
  • 62. RecapRecap 1. Each component should have only oneEach component should have only one responsibilityresponsibility 2. Prerender on the server for SEO, usability andPrerender on the server for SEO, usability and other benefitsother benefits 3. UJS will mount your component and take careUJS will mount your component and take care of the handoffof the handoff
  • 63. IsomorphicIsomorphic Javascript is theJavascript is the future.future. React Ember 2.0 with FastBoot Angular 2?
  • 64. Where we've come from andWhere we've come from and where we are goingwhere we are going 1. Constructing API's that serve JSON to the clientConstructing API's that serve JSON to the client 2. Preload your data on startup to avoid spinners andPreload your data on startup to avoid spinners and loading screensloading screens 3. Server-side rendering for SEO, startup time and a greatServer-side rendering for SEO, startup time and a great user experienceuser experience
  • 65. Thanks!Thanks! Would love to answer any questions Please feel free to tweet at me or get in touch in any other way. @danielspecs spector.io