TDC 2015 - Rails e Javascript: faça isso direito
-
Upload
cezinha-anjos -
Category
Software
-
view
53 -
download
0
Transcript of TDC 2015 - Rails e Javascript: faça isso direito
$ whoami• Cezinha Anjos.
• Comecei programando num Apple II e gravando programas em fitas cassetes há 26 anos atrás.
• Atualmente focado em Ruby on Rails e Javascript.
• Gosto de OO, Clean Code, Design Patterns, BDD e Lean.
• Diretor da ASSEINFO.
• Estamos localizados em Tijucas - SC - 40 km de Florianópolis.
• Somos em torno de 20 pessoas.
• Quase nenhuma verticalização hierárquica. Quem tem chefe é índio!
• Desde 2001 no mercado de automação comercial.
• Trabalhamos com ERP.
• Foco em qualidade.
• Já nascemos agile, mesmo antes de conhecer o manifesto ágil.
3
# Arquivo: Gemfile
source 'https://rubygems.org' gem 'rails', '4.2.0' gem 'sqlite3' gem 'sass-rails', '~> 5.0' gem 'uglifier', '>= 1.3.0' gem 'coffee-rails', '~> 4.1.0'gem 'jquery-rails'
Remover gems do front-end
Configuração
$ bower init
# enter, enter, enter, enter… # até que o arquivo bower.json # seja gerado
Configuração// Arquivo: bower.json
{ name: ‘rails-and-js’, version: '0.0.0', authors: [ 'Cezinha <[email protected]>' ], license: 'MIT', ignore: [ '**/.*', 'node_modules', 'bower_components', 'test', 'tests' ] }
Configuração
$ vim .bowerrc
{ "directory": "vendor/assets/bower" }
Caminho onde os pacotes serão baixadose a asset pipeline poderá utilizar.
Instalando dependências
$ bower install jquery#2.0.3 —-save
$ bower install jquery-ujs#1.0.3 --save
# Arquivo: Gemfile ... gem 'jquery-rails'
Instalando dependências// arquivo: bower.json { "name": "rails-and-js", "version": "0.0.0", "authors": [ "Cezinha <[email protected]>" ], "license": "MIT", "ignore": [ "**/.*", "node_modules", "bower_components", "test", "tests" ], "dependencies": { "jquery": "2.0.3", "jquery-ujs": "1.0.3" } }
Ajustando o manifesto
// arquivo: application.js //= require jquery
//= require_tree .//= require jquery_ujs//= require jquery-ujs
Você pode instalarcoisas como:• JQuery;
• JQuery UI;
• Twitter Bootstrap;
• Font Awesome;
• Angular JS;
• Backbone;
• React JS;
Qualquer projeto
que esteja no github
(ou similar)
$ mkdir app/assets/javascripts/views $ mkdir app/assets/javascripts/views/people
Uma pasta por view
Pelo menos um arquivo por action
// arquivo: app/assets/javascripts/views/people/index.js alert("Running index.js");
// arquivo: app/assets/javascripts/views/people/edit.js alert("Running edit.js");
// arquivo: app/assets/javascripts/views/people/show.js alert("Running show.js");
// arquivo: app/assets/javascripts/views/people/new.js alert("Running new.js");
// arquivo: application.js // na visão do sprockets // sem "uglificação" alert("Running edit.js"); alert("Running index.js"); alert("Running new.js"); alert("Running show.js");
Visão do sprockets
Você não tem como separar fisicamente os scripts sem aumentar o número de
requisições.
Minha opinião: não separe!
Ajustando o manifesto
// arquivo: application.js //= require jquery //= require jquery-ujs//= require_tree .//= require modulejs //= require_tree .
alert("Running index.js");
// arquivo: app/assets/javascripts/views/people/index.js
modulejs.define("people.index", function() { return function() { alert("Running index.js”); }; });
// Resultado do console: function () { alert("Running index.js"); }
1 2 3
4
var mymodule = modulejs.require("people.index"); console.log(mymodule); mymodule();
Carregamento da página
Executa JS de terceiros
Dispatcher (boot.js)
people/index.js
foo.js
people/new.js people/edit.js people/show.js
bar.js
x.js y.js
Fluxo de execução
Carregamento da página
Executa JS de terceiros
Dispatcher (boot.js)
people/index.js
foo.js
people/new.js people/edit.js people/show.js
bar.js
x.js y.js
Fluxo de execução
Carregamento da página
Executa JS de terceiros
Dispatcher (boot.js)
people/index.js
foo.js
people/new.js people/edit.js people/show.js
bar.js
x.js y.js
Fluxo de execução
Carregamento da página
Executa JS de terceiros
Dispatcher (boot.js)
people/index.js
foo.js
people/new.js people/edit.js people/show.js
bar.js
x.js y.js
Fluxo de execução
Carregamento da página
Executa JS de terceiros
Dispatcher (boot.js)
people/index.js
foo.js
people/new.js people/edit.js people/show.js
bar.js
x.js y.js
Fluxo de execução
Carregamento da página
Executa JS de terceiros
Dispatcher (boot.js)
people/index.js
foo.js
people/new.js people/edit.js people/show.js
bar.js
x.js y.js
Fluxo de execução
// arquivo app/assets/javascripts/boot.js (function() { "use strict"; $(document).ready(function() {
// Aqui deve ser o seu primeiro // ponto de execução de javascript
}); })()
Ajustando o manifesto// arquivo: application.js //= require jquery //= require jquery-ujs //= require modulejs//= require_tree .//= require boot//= require_tree ./views
// arquivo app/assets/javascripts/boot.js (function() { "use strict"; $(document).ready(function() {
}); })()
// Aqui deve ser o seu primeiro // ponto de execução de javascript //
modulejs.define("people.index", function() { return function() { alert("Running index.js") }; });
// arquivo: app/assets/javascripts/views/people/index.js
var mymodule = modulejs.require("people.index"); console.log(mymodule); mymodule();
// arquivo app/assets/javascripts/boot.js (function() { "use strict"; $(document).ready(function() {
}); })()
// Aqui deve ser o seu primeiro // ponto de execução de javascript //
modulejs.define("people.index", function() { return function() { alert("Running index.js") }; });
// arquivo: app/assets/javascripts/views/people/index.js
var mymodule = modulejs.require("people.index"); console.log(mymodule); mymodule();
// arquivo app/assets/javascripts/boot.js (function() { "use strict"; $(document).ready(function() {
}); })()
// Aqui deve ser o seu primeiro // ponto de execução de javascript //
modulejs.define("people.index", function() { return function() { alert("Running index.js") }; });
// arquivo: app/assets/javascripts/views/people/index.js
var mymodule = modulejs.require("people.index"); console.log(mymodule); mymodule();
var mymodule = modulejs.require("people.index"); console.log(mymodule); mymodule();
// arquivo app/assets/javascripts/boot.js (function() { "use strict"; $(document).ready(function() {
var mymodule = modulejs.require("people.index"); console.log(mymodule); mymodule();
}); })()
// arquivo app/assets/javascripts/boot.js (function() { "use strict"; $(document).ready(function() {
var mymodule = modulejs.require("people.index"); console.log(mymodule); mymodule();
}); })()
A action está hard coded neste ponto!
<body dispatcher="people.index">
<!-- arquivo: app/views/layouts/application.html.erb --> <body <%= dispatcher_tag %>>
<body dispatcher="people.index">
<!-- arquivo: app/views/layouts/application.html.erb --> <body <%= dispatcher_tag %>>
Criaremos um helper para “batizar" a tag body
<body dispatcher="people.index">
# arquivo: app/helpers/application_helper.rb module ApplicationHelper def dispatcher_tag controller_name = controller.class.name.underscore controller_name.gsub!(/\//, "_") controller_name.gsub!(/_controller$/, "") div_tag = %(dispatcher="#{controller_name}.#{controller.action_name}") div_tag.html_safe end end
<body dispatcher="people.index">
# arquivo: app/helpers/application_helper.rb module ApplicationHelper def dispatcher_tag controller_name = controller.class.name.underscore controller_name.gsub!(/\//, "_") controller_name.gsub!(/_controller$/, "") div_tag = %(dispatcher="#{controller_name}.#{controller.action_name}") div_tag.html_safe end end
// arquivo app/assets/javascripts/boot.js (function() { "use strict"; $(document).ready(function() {
var mymodule = modulejs.require("people.index"); console.log(mymodule); mymodule();
}); })()
A action está hard coded neste ponto!
<body dispatcher="people.index">
// arquivo app/assets/javascripts/boot.js (function() { "use strict"; $(document).ready(function() {
var mymodule = modulejs.require("people.index"); console.log(mymodule); mymodule();
}); })()
<body dispatcher="people.index">
var dispatch_to = $("body").attr("dispatcher");
// arquivo app/assets/javascripts/boot.js (function() { "use strict"; $(document).ready(function() {
var mymodule = modulejs.require("people.index"); console.log(mymodule); mymodule();
}); })()
<body dispatcher="people.index">
var dispatch_to = $("body").attr("dispatcher");
// arquivo app/assets/javascripts/boot.js (function() { "use strict"; $(document).ready(function() {
var mymodule = modulejs.require(dispatch_to); console.log(mymodule); mymodule();
}); })()
<body dispatcher="people.index">
var dispatch_to = $("body").attr("dispatcher");
// arquivo app/assets/javascripts/boot.js (function() { "use strict"; $(document).ready(function() {
var mymodule = modulejs.require(dispatch_to); console.log(mymodule); mymodule();
}); })()
<body dispatcher="people.index">
var dispatch_to = $("body").attr("dispatcher");
# arquivo: app/controllers/people_controller.rb ... def index @people = Person.all respond_to do |format| format.html format.json { render json: @people.to_json } end end ...
class PostSerializer < ActiveModel::Serializer attributes :title, :body
has_many :comments end
class CommentSerializer < ActiveModel::Serializer attributes :name, :body
belongs_to :post end
[ { "title":"Obama mentiu sobre operação que matou Bin Laden", "body":"O jornalista Seymour Hersh, que recebeu o Prêmio Pulitzer…”, "comments": [ { "name":"Fulano", "body":"Eu não acredito!" } ] } ]
Rails.application.routes.draw do resources :people end
people GET /people(.:format) people#index new_person GET /people/new(.:format) people#new
edit_person GET /people/:id/edit(.:format) people#edit person GET /people/:id(.:format) people#show
$ bin/rake routes
✔
✘
# Arquivo: Gemfile
source 'https://rubygems.org' gem 'rails', '4.2.0' gem 'sqlite3' gem 'sass-rails', '~> 5.0' gem 'uglifier', '>= 1.3.0' gem 'coffee-rails', '~> 4.1.0’ gem 'jquery-rails'gem 'js-routes'
//= require_tree ./views //= require boot//= require js-routes //= require_tree ./views //= require boot
Ajustando o manifesto
// arquivo: application.js //= require jquery //= require jquery-ujs //= require modulejs
Routes.people_path() "/people.json" Routes.new_person_path() "/people/new.json" Routes.edit_person_path(1) "/people/1/edit.json" Routes.person_path(1) "/people/1.json"
# Arquivo: Gemfile
source 'https://rubygems.org' gem 'rails', '4.2.0' gem 'sqlite3' gem 'sass-rails', '~> 5.0' gem 'uglifier', '>= 1.3.0' gem 'coffee-rails', '~> 4.1.0’ gem 'jquery-rails' gem 'js-routes'gem 'ejs'
Ajustando o manifesto
//= require_tree ./views //= require boot//= require_tree ./templates //= require_tree ./views //= require boot
// arquivo: application.js //= require jquery //= require jquery-ujs //= require modulejs //= require js-routes
<!-- arquivo: app/assets/javascripts/templates/people/example.jst.ejs --> <p>Name:</p> <p><%= name %></p> <p>Phone:</p> <p><%= phone %></p>
Criando um template
(function() { "use strict" var html = JST["templates/people/example"]({ name: "The name", phone: "(48) 1234-5678" }); $("div#person").html(html); }())
Consumindo um template
<p>Name:</p> <p><%= name %></p> <p>Phone:</p> <p><%= phone %></p>
(function() { "use strict" var html = JST["templates/people/example"]({ name: "The name", phone: "(48) 1234-5678" }); $("div#person").html(html); }())
Consumindo um template
<p>Name:</p> <p><%= name %></p> <p>Phone:</p> <p><%= phone %></p>
Array de templatescompilados
(function() { "use strict" var html = JST["templates/people/example"]({ name: "The name", phone: "(48) 1234-5678" }); $("div#person").html(html); }())
Consumindo um template
<p>Name:</p> <p><%= name %></p> <p>Phone:</p> <p><%= phone %></p>
A chave do arrayé o path dotemplate
(function() { "use strict" var html = JST["templates/people/example"]({ name: "The name", phone: "(48) 1234-5678" }); $("div#person").html(html); }())
Consumindo um template
<p>Name:</p> <p><%= name %></p> <p>Phone:</p> <p><%= phone %></p>
O conteúdo doarray é uma função
(function() { "use strict" var html = JST["templates/people/example"]({ name: "The name", phone: "(48) 1234-5678" }); $("div#person").html(html); }())
Consumindo um template
<p>Name:</p> <p><%= name %></p> <p>Phone:</p> <p><%= phone %></p>
Objeto literal com parâmetros do template
(function() { "use strict" var html = JST["templates/people/example"]({ name: "The name", phone: "(48) 1234-5678" }); $("div#person").html(html); }())
Consumindo um template
<p>Name:</p> <p><%= name %></p> <p>Phone:</p> <p><%= phone %></p>
Use o html resul-tante como quiser
var foo = "value outside IIFE"; (function() { var foo = "value inside IIFE"; console.log(foo); }()) console.log(foo);
// Resultado: // value inside IIFE // value outside IIFE
(function () { "use strict"; // Introduzido no ECMA 5. // Converte enganos em erros. // Simplifica o uso de variáveis. // Simplifica "eval" e argumentos. // Ajuda a escrever JS mais seguro. // // Referência: Mozilla Developer Network }())
(function () { foo = "this should be a private content"; }())
Falta do "var" fará de "foo" global
Falta do “use strict" fará não gerar erro
(function () { foo = "this should be a private content"; }())
"use strict";
ReferenceError: Can’t find variable foo
(function () { foo = "this should be a private content"; }())
"use strict";
var foo = "this should be a private content";
var promise; promise = $.get("/people.json"); promise.done(function(data) { alert("done"); alert(JSON.stringify(data)); }); promise.fail(function(error) { alert("fail"); alert("status text:" + error.statusText); }); promise.always(function() { alert("always"); });