Globalcode	
  – Open4education
Interfaces  ricas  com  Rails  e  React.JS
Rodrigo  Urubatan
@urubatan
Globalcode	
  – Open4education
Quem?
Programador  desde  1997
Trabalha  com  Ruby  na  Brightwire
Escreveu  "Ruby  On  Rails:  Desenvolvimento  fácil  e  Rápido  de  
aplicações  web”
Já  trabalhou  com  diversas  linguagens  (C,  C++,  Delphi,  PHP,  
ASP,  ColdFusion,  VisualBasic,  C#,  Python,  Ruby,  Assembly,  
…)
Apaixonado  por  Agile  e  atualmente  por  trabalho  remoto
Patinador,  Corredor,  Ciclista  e  agora  resolveu  aprender  Karate  
:D
Pai  de  um  Guri  de  6  anos
http://urubatan.com.br -­ Anda  meio  abandonado  mas  vai  voltar
http://sobrecodigo.com -­ idem
Globalcode	
  – Open4education
Objetivo
Usar  o  Rails  como  backend  da  aplicação
Toda  a  interação  com  o  usuário  será  implementada  
no  cliente
Validações  e  regras  de  negócio  serão  
implementadas  no  servidor
(sim,  eu  poderia  usar  Sinatra  mas  sou  preguiçoso)
Globalcode	
  – Open4education
Cuidado!
Nesta  palestra  vamos  falar  de  uma  SPA  (Single  
Page  Application)
Isto  tem  vantagens  e  desvantagens
Melhora  muito  a  interação  com  o  usuário  sem  
duplicação  de  código,  já  que  o  código  de  
renderização  fica  todo  no  JS
Piora  muito  a  indexação  da  sua  aplicação  por  
buscadores  (adeus  SEO  -­ ou  não…)
Globalcode	
  – Open4education
O  que,  quando,  onde  e  por  
que?
Muitas  aplicações  hoje  em  dia  exigem  um  nível  alto  
de  interação  com  o  usuário
Implementar  isto  usando  bibliotecas  mais  baixo  
nível  é  muito  fácil  de  causar  uma  grande  
confusão  do  código  (PHP  alguem?)
Componentização  evita  duplicação  de  código  e  
facilita  a  organização
Globalcode	
  – Open4education
Por que rails?
Eu gosto :P
Globalcode	
  – Open4education
Por que React.js?
JSX!!!!!!
Unir o  código  Javascript  e  o  Código  HTML  de  
cada  componente  
Facilidade  de  manutenção  
Facilidade  de  organização  
Mantem  o  CSS  separado  de  propósito,  CSS  é  
mais  especifico  de  aplicação  do  que  
componente  (pode  se  usar  imports  SASS  se  
necessário)  
Globalcode	
  – Open4education
Por que React.js?
Virtual  DOM
Fácil  de  testar  em  uma  pequena  parte  de  uma  tela  
Renderização  reativa  
Componentes  stateful  
Comunicação  entre  componentes  via  propriedades  
Globalcode	
  – Open4education
Mãos  a  obra!  (O  blog  mais
feio do  mundo!)
Globalcode	
  – Open4education
Criando  a  aplicação
Uma  aplicação  padrão  Rails  (rails  new  …)
Gemfile  updates
gem 'backbone-on-rails'
gem 'react-rails', github: 'reactjs/react-rails', ref:
'master'
Environment  update  (development.rb  para  
começar)
config.react.variant = :development
config.react.addons = true # defaults to false
config.react.server_renderer =
React::ServerRendering::SprocketsRenderer
bundle  install
rails  g  react:install
Globalcode	
  – Open4education
Componentes
Componentes  javascript  vão  ficar  em  
app/assets/javascript/components
Backbone.js  vai  facilitar  a  comunicação  
cliente/servidor
arquivos  .js.jsx  tem  uma  facilidade  extra,  são  
compilados  pelo  react-­rails  via  asset  pipeline  e  
permitem  adicionar  HTML  inline  
Globalcode	
  – Open4education
Cadastrando  um  Post
rails  g  scaffold  post  title:string slug:text content:text
Apagar todas as  views  do  post  exceto index.html.erb
Globalcode	
  – Open4education
Alterações  no  controller
Fazer  todos  os  métodos  retornarem  json
Remover  edit,  new  e  show
Apagar  todo  o  código  de  index.html.erb  e  
mudar  para:
<%=  react_component('Blog',  {collection:  
@posts,  item:  @post})  %>
Globalcode	
  – Open4education
Agora  mãos  a  obra
já  temos  uma  “API"  em  Rails,  poderíamos  ter  o  
código  em  Sinatra  que  seria  mais  leve,  mas  eu  
gosto  do  asset  pipeline  e  assim  fica  mais  fácil  para  
um  iniciante
Falta  criar  os  componentes  backbone  para  acessar  
o  backend
Criar  os  componentes  react  para  a  UI
Globalcode	
  – Open4education
backbone.js
app/assets/javascripts/collections/posts.js
var Posts  =  Backbone.Collection.extend({
model:  Post,
url:  '/posts'
});;
app/assets/jaascripts/models/post.js
var Post  =  Backbone.Model.extend({
});;
Globalcode	
  – Open4education
blog.js.jsx
var Blog  =  React.createClass({
…..
render:  function  ()  {
if(this.state.editing)   {
return  (<div>
<div  id="blogList">
<PostList collection={this.state.collection}   viewModel={this.viewModel}  
newModel={this.newModel}/>
</div>
<div  id="blogPost">
<PostForm collection={this.state.collection}   model={this.state.model}  
viewModel={this.viewModel}/>
</div>
</div>);;
}else{
return  (<div>
<div  id="blogList">
<PostList collection={this.state.collection}   viewModel={this.viewModel}  
newModel={this.newModel}/>
</div>
<div  id="blogPost">
<PostView model={this.state.model}   editModel={this.editModel}/>
</div>
</div>);;
}
}
});;
Globalcode	
  – Open4education
post_list.js.jsx
var PostList =  React.createClass({
….
render:  function  ()  {
var users  =  this.props.collection.map(function  (model)  {
var viewModel =  function  ()  {
this.props.viewModel(model);;
};;
return  (
<tr key={model.get("id")}>
<td><a  href="#"  onClick={viewModel.bind(this)}>{model.get("title")}</a></td>
<td>{new  Date(model.get("created_at")).toDateString()}</td>
</tr>
);;
}.bind(this));;
return  (
<div>
<table  className="post-­list">
<thead>
<tr>
<th>Post</th>
<th>Published</th>
</tr>
</thead>
<tbody>
{users}
</tbody>
</table>
<hr/>
<a  href="#"  onClick={this.props.newModel}>Create  post</a>
</div>
);;
}
});;
Globalcode	
  – Open4education
post_view.js.jsx
var PostView =  React.createClass({
editModel:  function  ()  {
this.props.editModel(this.props.model);;
},
render:  function  ()  {
var innerLines =  null;;
if(this.props.model.get("content"))   {
innerLines=_.map(this.props.model.get("content").split("n"),   function  (txt,  idx)  {
return  <p  key={idx}>{txt}</p>
});;
}
return  (
<div  className="blog-­post">
<h1><a  
href={this.props.model.get("slug")}>{this.props.model.get("title")}</a></h1>
<div  className="post-­body">
{innerLines}
</div>
<hr/>
<a  href="#"  onClick={this.editModel}>Edit  post</a>
</div>
);;
}
});;
Globalcode	
  – Open4education
post_form.js.jsx
var PostForm =  React.createClass({
saveModel:  function  ()  {
if  (this.props.model.get("id"))  {
this.props.model.save();;
}  else  {
this.props.collection.create(this.props.model);;
}
this.props.viewModel(this.props.model)
},
render:  function  ()  {
return  (
<div  className="blog-­post">
<InputWithLabel model={this.props.model}  label="Title"  name="title"  type="text"/>
<InputWithLabel model={this.props.model}  label="Body"  name="content"  type="textarea"/>
<div  className="form-­field">
<button  onClick={this.saveModel}>Save</button>
</div>
</div>
);;
}
});;
Globalcode	
  – Open4education
input_with_label.js.jsx
var InputWithLabel = React.createClass({
handleChange: function(event) {
this.props.model.set(this.props.name,event.target.value)
},
render: function() {
return <div className="form-field">
<label htmlFor={this.props.name}>{this.props.label}</label>
<div>
<input id={this.props.name} type={this.props.type} name={this.props.name} ref="input"
onChange={this.handleChange} value={this.props.model.get(this.props.name)}/>
</div>
</div>;
}
});
Globalcode	
  – Open4education
Globalcode	
  – Open4education
indexação?  performance?
renderização  no  servidor:
<%=  react_component('Layout',  {collection:  
@users},  {prerender:  true})  %>
components.js
//=  require  underscore
//=  require  backbone
//=  require_tree  ./models
//=  require_tree  ./collections
//=  require_tree  ./components
Globalcode	
  – Open4education
Mas  é  só  isto?
React-­router
Backbone.Router
Flux  -­ arquitetura  JS  usada  pelo  Facebook
Globalcode	
  – Open4education

TDC2015 Porto Alegre - Interfaces ricas com Rails e React.JS

  • 1.
    Globalcode  – Open4education Interfaces ricas  com  Rails  e  React.JS Rodrigo  Urubatan @urubatan
  • 2.
    Globalcode  – Open4education Quem? Programador desde  1997 Trabalha  com  Ruby  na  Brightwire Escreveu  "Ruby  On  Rails:  Desenvolvimento  fácil  e  Rápido  de   aplicações  web” Já  trabalhou  com  diversas  linguagens  (C,  C++,  Delphi,  PHP,   ASP,  ColdFusion,  VisualBasic,  C#,  Python,  Ruby,  Assembly,   …) Apaixonado  por  Agile  e  atualmente  por  trabalho  remoto Patinador,  Corredor,  Ciclista  e  agora  resolveu  aprender  Karate   :D Pai  de  um  Guri  de  6  anos http://urubatan.com.br -­ Anda  meio  abandonado  mas  vai  voltar http://sobrecodigo.com -­ idem
  • 3.
    Globalcode  – Open4education Objetivo Usar o  Rails  como  backend  da  aplicação Toda  a  interação  com  o  usuário  será  implementada   no  cliente Validações  e  regras  de  negócio  serão   implementadas  no  servidor (sim,  eu  poderia  usar  Sinatra  mas  sou  preguiçoso)
  • 4.
    Globalcode  – Open4education Cuidado! Nesta palestra  vamos  falar  de  uma  SPA  (Single   Page  Application) Isto  tem  vantagens  e  desvantagens Melhora  muito  a  interação  com  o  usuário  sem   duplicação  de  código,  já  que  o  código  de   renderização  fica  todo  no  JS Piora  muito  a  indexação  da  sua  aplicação  por   buscadores  (adeus  SEO  -­ ou  não…)
  • 5.
    Globalcode  – Open4education O que,  quando,  onde  e  por   que? Muitas  aplicações  hoje  em  dia  exigem  um  nível  alto   de  interação  com  o  usuário Implementar  isto  usando  bibliotecas  mais  baixo   nível  é  muito  fácil  de  causar  uma  grande   confusão  do  código  (PHP  alguem?) Componentização  evita  duplicação  de  código  e   facilita  a  organização
  • 6.
  • 7.
    Globalcode  – Open4education Porque React.js? JSX!!!!!! Unir o  código  Javascript  e  o  Código  HTML  de   cada  componente   Facilidade  de  manutenção   Facilidade  de  organização   Mantem  o  CSS  separado  de  propósito,  CSS  é   mais  especifico  de  aplicação  do  que   componente  (pode  se  usar  imports  SASS  se   necessário)  
  • 8.
    Globalcode  – Open4education Porque React.js? Virtual  DOM Fácil  de  testar  em  uma  pequena  parte  de  uma  tela   Renderização  reativa   Componentes  stateful   Comunicação  entre  componentes  via  propriedades  
  • 9.
    Globalcode  – Open4education Mãos a  obra!  (O  blog  mais feio do  mundo!)
  • 10.
    Globalcode  – Open4education Criando a  aplicação Uma  aplicação  padrão  Rails  (rails  new  …) Gemfile  updates gem 'backbone-on-rails' gem 'react-rails', github: 'reactjs/react-rails', ref: 'master' Environment  update  (development.rb  para   começar) config.react.variant = :development config.react.addons = true # defaults to false config.react.server_renderer = React::ServerRendering::SprocketsRenderer bundle  install rails  g  react:install
  • 11.
    Globalcode  – Open4education Componentes Componentes javascript  vão  ficar  em   app/assets/javascript/components Backbone.js  vai  facilitar  a  comunicação   cliente/servidor arquivos  .js.jsx  tem  uma  facilidade  extra,  são   compilados  pelo  react-­rails  via  asset  pipeline  e   permitem  adicionar  HTML  inline  
  • 12.
    Globalcode  – Open4education Cadastrando um  Post rails  g  scaffold  post  title:string slug:text content:text Apagar todas as  views  do  post  exceto index.html.erb
  • 13.
    Globalcode  – Open4education Alterações no  controller Fazer  todos  os  métodos  retornarem  json Remover  edit,  new  e  show Apagar  todo  o  código  de  index.html.erb  e   mudar  para: <%=  react_component('Blog',  {collection:   @posts,  item:  @post})  %>
  • 14.
    Globalcode  – Open4education Agora mãos  a  obra já  temos  uma  “API"  em  Rails,  poderíamos  ter  o   código  em  Sinatra  que  seria  mais  leve,  mas  eu   gosto  do  asset  pipeline  e  assim  fica  mais  fácil  para   um  iniciante Falta  criar  os  componentes  backbone  para  acessar   o  backend Criar  os  componentes  react  para  a  UI
  • 15.
    Globalcode  – Open4education backbone.js app/assets/javascripts/collections/posts.js varPosts  =  Backbone.Collection.extend({ model:  Post, url:  '/posts' });; app/assets/jaascripts/models/post.js var Post  =  Backbone.Model.extend({ });;
  • 16.
    Globalcode  – Open4education blog.js.jsx varBlog  =  React.createClass({ ….. render:  function  ()  { if(this.state.editing)   { return  (<div> <div  id="blogList"> <PostList collection={this.state.collection}   viewModel={this.viewModel}   newModel={this.newModel}/> </div> <div  id="blogPost"> <PostForm collection={this.state.collection}   model={this.state.model}   viewModel={this.viewModel}/> </div> </div>);; }else{ return  (<div> <div  id="blogList"> <PostList collection={this.state.collection}   viewModel={this.viewModel}   newModel={this.newModel}/> </div> <div  id="blogPost"> <PostView model={this.state.model}   editModel={this.editModel}/> </div> </div>);; } } });;
  • 17.
    Globalcode  – Open4education post_list.js.jsx varPostList =  React.createClass({ …. render:  function  ()  { var users  =  this.props.collection.map(function  (model)  { var viewModel =  function  ()  { this.props.viewModel(model);; };; return  ( <tr key={model.get("id")}> <td><a  href="#"  onClick={viewModel.bind(this)}>{model.get("title")}</a></td> <td>{new  Date(model.get("created_at")).toDateString()}</td> </tr> );; }.bind(this));; return  ( <div> <table  className="post-­list"> <thead> <tr> <th>Post</th> <th>Published</th> </tr> </thead> <tbody> {users} </tbody> </table> <hr/> <a  href="#"  onClick={this.props.newModel}>Create  post</a> </div> );; } });;
  • 18.
    Globalcode  – Open4education post_view.js.jsx varPostView =  React.createClass({ editModel:  function  ()  { this.props.editModel(this.props.model);; }, render:  function  ()  { var innerLines =  null;; if(this.props.model.get("content"))   { innerLines=_.map(this.props.model.get("content").split("n"),   function  (txt,  idx)  { return  <p  key={idx}>{txt}</p> });; } return  ( <div  className="blog-­post"> <h1><a   href={this.props.model.get("slug")}>{this.props.model.get("title")}</a></h1> <div  className="post-­body"> {innerLines} </div> <hr/> <a  href="#"  onClick={this.editModel}>Edit  post</a> </div> );; } });;
  • 19.
    Globalcode  – Open4education post_form.js.jsx varPostForm =  React.createClass({ saveModel:  function  ()  { if  (this.props.model.get("id"))  { this.props.model.save();; }  else  { this.props.collection.create(this.props.model);; } this.props.viewModel(this.props.model) }, render:  function  ()  { return  ( <div  className="blog-­post"> <InputWithLabel model={this.props.model}  label="Title"  name="title"  type="text"/> <InputWithLabel model={this.props.model}  label="Body"  name="content"  type="textarea"/> <div  className="form-­field"> <button  onClick={this.saveModel}>Save</button> </div> </div> );; } });;
  • 20.
    Globalcode  – Open4education input_with_label.js.jsx varInputWithLabel = React.createClass({ handleChange: function(event) { this.props.model.set(this.props.name,event.target.value) }, render: function() { return <div className="form-field"> <label htmlFor={this.props.name}>{this.props.label}</label> <div> <input id={this.props.name} type={this.props.type} name={this.props.name} ref="input" onChange={this.handleChange} value={this.props.model.get(this.props.name)}/> </div> </div>; } });
  • 21.
  • 22.
    Globalcode  – Open4education indexação? performance? renderização  no  servidor: <%=  react_component('Layout',  {collection:   @users},  {prerender:  true})  %> components.js //=  require  underscore //=  require  backbone //=  require_tree  ./models //=  require_tree  ./collections //=  require_tree  ./components
  • 23.
    Globalcode  – Open4education Mas é  só  isto? React-­router Backbone.Router Flux  -­ arquitetura  JS  usada  pelo  Facebook
  • 24.