O que há de novo no Rails 3
-
Upload
hugo-barauna -
Category
Technology
-
view
2.758 -
download
0
description
Transcript of O que há de novo no Rails 3
Hugo Baraúna @hugobaraunablog.plataformatec.com
Rails 3
Hugo Baraúna @hugobaraunablog.plataformatec.com
blog twitterID
Rails 3
Hugo Baraúna @hugobaraunablog.plataformatec.com
Quem sou eu?
• Hugo Baraúna
• 24 anos
• Engenharia de Computação na Politécnica da USP
•Desenvolvedor Ruby e Rails há mais de 3 anos
• Co-fundador e engenheiro da Plataforma Tecnologia
Hugo Baraúna @hugobaraunablog.plataformatec.com
Hugo Baraúna @hugobaraunablog.plataformatec.com
Desevolvemosaplicações em Rails
ConsultoriaCoaching em Rails e Agile
Hugo Baraúna @hugobaraunablog.plataformatec.com
Arquitetura
ActionDispatch
ActiveSupport
Rails
Rails 3
Hugo Baraúna @hugobaraunablog.plataformatec.com
Arquitetura
ActionDispatch
ActiveSupport
Rails
Rails 3
Todo o resto são Railties!
Hugo Baraúna @hugobaraunablog.plataformatec.com
Arquitetura
ActionDispatch
ActiveSupport
Rails
Rails 3
Todo o resto são Railties!
ActiveRecord
ActionMailer
ActionController
ActionView
outros...
Hugo Baraúna @hugobaraunablog.plataformatec.com
Vantagens do Rails 3
Hugo Baraúna @hugobaraunablog.plataformatec.com
Vantagens do Rails 3
Performance
Hugo Baraúna @hugobaraunablog.plataformatec.com
Vantagens do Rails 3
Performance
Agnóstico
Hugo Baraúna @hugobaraunablog.plataformatec.com
Vantagens do Rails 3
Performance
Modularidade
Agnóstico
Hugo Baraúna @hugobaraunablog.plataformatec.com
Instalação
guru/code$ gem install tzinfo builder memcache-client rack rack-test rack-mount erubis mail text-format thor bundler i18n
guru/code$ gem install rails --pre
Hugo Baraúna @hugobaraunablog.plataformatec.com
rails command
ruby script/serverruby script/consoleruby script/generateruby script/dbconsole
rails consolerails generaterails dbconsole
rails server
Rails 2.3 Rails 3
Hugo Baraúna @hugobaraunablog.plataformatec.com
blog/config.ru
require ::File.expand_path('../config/environment', __FILE__)run Blog::Application
Hugo Baraúna @hugobaraunablog.plataformatec.com
blog/config.ru
require ::File.expand_path('../config/environment', __FILE__)run Blog::Application
Hugo Baraúna @hugobaraunablog.plataformatec.com
blog/config/application.rbrequire File.expand_path('../boot', __FILE__)require 'rails/all'
Bundler.require(:default, Rails.env) if defined?(Bundler)
module Blog class Application < Rails::Application config.encoding = "utf-8" config.filter_parameters += [:password] endend
Hugo Baraúna @hugobaraunablog.plataformatec.com
blog/config/application.rbrequire File.expand_path('../boot', __FILE__)require 'rails/all'
Bundler.require(:default, Rails.env) if defined?(Bundler)
module Blog class Application < Rails::Application config.encoding = "utf-8" config.filter_parameters += [:password] endend
uma Rack App!
Hugo Baraúna @hugobaraunablog.plataformatec.com
blog/config/application.rbrequire File.expand_path('../boot', __FILE__)require 'rails/all'
Bundler.require(:default, Rails.env) if defined?(Bundler)
module Blog class Application < Rails::Application config.encoding = "utf-8" config.filter_parameters += [:password] endend
Hugo Baraúna @hugobaraunablog.plataformatec.com
blog/config/application.rbrequire File.expand_path('../boot', __FILE__)require 'rails/all'
Bundler.require(:default, Rails.env) if defined?(Bundler)
module Blog class Application < Rails::Application config.encoding = "utf-8" config.filter_parameters += [:password] endend
Hugo Baraúna @hugobaraunablog.plataformatec.com
blog/config/boot.rbrequire 'rubygems'
# Set up gems listed in the Gemfile.gemfile = File.expand_path('../../Gemfile', __FILE__)begin ENV['BUNDLE_GEMFILE'] = gemfile require 'bundler' Bundler.setuprescue Bundler::GemNotFound => e STDERR.puts e.message STDERR.puts "Try running `bundle install`." exit!end if File.exist?(gemfile)
Hugo Baraúna @hugobaraunablog.plataformatec.com
blog/config/boot.rbrequire 'rubygems'
# Set up gems listed in the Gemfile.gemfile = File.expand_path('../../Gemfile', __FILE__)begin ENV['BUNDLE_GEMFILE'] = gemfile require 'bundler' Bundler.setuprescue Bundler::GemNotFound => e STDERR.puts e.message STDERR.puts "Try running `bundle install`." exit!end if File.exist?(gemfile)
Hugo Baraúna @hugobaraunablog.plataformatec.com
BundlerRouterActionMailerActiveModelRespondersARelUnobtrusive JavascriptXSS Protection
Hugo Baraúna @hugobaraunablog.plataformatec.com
Hugo Baraúna @hugobaraunablog.plataformatec.com
Biblioteca para gerenciamento de dependências
Hugo Baraúna @hugobaraunablog.plataformatec.com
# Gemfilesource 'http://rubygems.org'
# Bundle edge Rails instead:gem 'rails', :git => 'git://github.com/rails/rails.git'gem 'mysql'gem 'devise', :git => 'git://github.com/plataformatec/devise.git'gem 'responders', :git => 'git://github.com/plataformatec/responders.git'
group :development do gem 'ruby-debug'end
group :test do gem 'rspec' gem 'rspec-rails', '>= 2.0.0.beta'end
Hugo Baraúna @hugobaraunablog.plataformatec.com
# Gemfilesource 'http://rubygems.org'
# Bundle edge Rails instead:gem 'rails', :git => 'git://github.com/rails/rails.git'gem 'mysql'gem 'devise', :git => 'git://github.com/plataformatec/devise.git'gem 'responders', :git => 'git://github.com/plataformatec/responders.git'
group :development do gem 'ruby-debug'end
group :test do gem 'rspec' gem 'rspec-rails', '>= 2.0.0.beta'end
Hugo Baraúna @hugobaraunablog.plataformatec.com
# Gemfilesource 'http://rubygems.org'
# Bundle edge Rails instead:gem 'rails', :git => 'git://github.com/rails/rails.git'gem 'mysql'gem 'devise', :git => 'git://github.com/plataformatec/devise.git'gem 'responders', :git => 'git://github.com/plataformatec/responders.git'
group :development do gem 'ruby-debug'end
group :test do gem 'rspec' gem 'rspec-rails', '>= 2.0.0.beta'end
Hugo Baraúna @hugobaraunablog.plataformatec.com
Resolução de dependências
Hugo Baraúna @hugobaraunablog.plataformatec.com
guru/code$ gem dependency actionpack -v="2.3.5"Gem actionpack-2.3.5 activesupport (= 2.3.5, runtime) rack (~> 1.0.0, runtime)
guru/code$ gem dependency thinGem thin-1.2.7 daemons (>= 1.0.9, runtime) eventmachine (>= 0.12.6, runtime) rack (>= 1.0.0, runtime)
Resolução de dependências
Hugo Baraúna @hugobaraunablog.plataformatec.com
guru/code$ gem dependency actionpack -v="2.3.5"Gem actionpack-2.3.5 activesupport (= 2.3.5, runtime) rack (~> 1.0.0, runtime)
guru/code$ gem dependency thinGem thin-1.2.7 daemons (>= 1.0.9, runtime) eventmachine (>= 0.12.6, runtime) rack (>= 1.0.0, runtime)
Resolução de dependências
Hugo Baraúna @hugobaraunablog.plataformatec.com
Resolução de dependências
require "rubygems"require "thin"gem "actionpack", "2.3.5"
Hugo Baraúna @hugobaraunablog.plataformatec.com
Resolução de dependências
require "rubygems"require "thin"gem "actionpack", "2.3.5"
can't activate rack (~> 1.0.0, runtime) for ["actionpack-2.3.5"], already activated rack-1.1.0 for
["thin-1.2.7"] (Gem::LoadError)
Hugo Baraúna @hugobaraunablog.plataformatec.com
Gemfile# Gemfilegem "thin"gem "actionpack", "2.3.5"
Hugo Baraúna @hugobaraunablog.plataformatec.com
Gemfile# Gemfilegem "thin"gem "actionpack", "2.3.5"
guru/code$ bundle listGems included by the bundle: * actionpack (2.3.5) * activesupport (2.3.5) * daemons (1.0.10) * eventmachine (0.12.10) * rack (1.0.1) * thin (1.2.7)
Hugo Baraúna @hugobaraunablog.plataformatec.com
Gemfile# Gemfilegem "thin"gem "actionpack", "2.3.5"
guru/code$ bundle listGems included by the bundle: * actionpack (2.3.5) * activesupport (2.3.5) * daemons (1.0.10) * eventmachine (0.12.10) * rack (1.0.1) * thin (1.2.7)
Hugo Baraúna @hugobaraunablog.plataformatec.com
Lock no $LOAD_PATH
Hugo Baraúna @hugobaraunablog.plataformatec.com
Esqueci de colocar no config.gem!
Hugo Baraúna @hugobaraunablog.plataformatec.com
Esqueci de colocar no config.gem!
Hugo Baraúna @hugobaraunablog.plataformatec.com
guru/code$ gem list*** LOCAL GEMS ***
bundler (0.9.25)rake (0.8.7, 0.8.5)rdoc (2.5.8)thor (0.13.6)
} Filesystem
Hugo Baraúna @hugobaraunablog.plataformatec.com
guru/code$ gem list*** LOCAL GEMS ***
bundler (0.9.25)rake (0.8.7, 0.8.5)rdoc (2.5.8)thor (0.13.6)
} Filesystem
# Gemfilegem “rake”, “0.8.5” } Gemfile
Hugo Baraúna @hugobaraunablog.plataformatec.com
guru/code$ gem list*** LOCAL GEMS ***
bundler (0.9.25)rake (0.8.7, 0.8.5)rdoc (2.5.8)thor (0.13.6)
} Filesystem
# Gemfilegem “rake”, “0.8.5” } Gemfile
rake-0.8.5 } $LOAD_PATH
Hugo Baraúna @hugobaraunablog.plataformatec.com
guru/code$ gem listrake (0.8.7, 0.8.5)thor (0.13.6)
Hugo Baraúna @hugobaraunablog.plataformatec.com
# Gemfilegem "rake"
guru/code$ gem listrake (0.8.7, 0.8.5)thor (0.13.6)
Hugo Baraúna @hugobaraunablog.plataformatec.com
# Gemfilegem "rake"
# test_load_path_lock.rbrequire "rubygems"require "bundler"Bundler.setuprequire "rake"require "thor"
guru/code$ gem listrake (0.8.7, 0.8.5)thor (0.13.6)
Hugo Baraúna @hugobaraunablog.plataformatec.com
# Gemfilegem "rake"
# test_load_path_lock.rbrequire "rubygems"require "bundler"Bundler.setuprequire "rake"require "thor"
guru/code$ gem listrake (0.8.7, 0.8.5)thor (0.13.6)
Lock no $LOAD_PATH
Hugo Baraúna @hugobaraunablog.plataformatec.com
# Gemfilegem "rake"
# test_load_path_lock.rbrequire "rubygems"require "bundler"Bundler.setuprequire "rake"require "thor"
guru/code$ gem listrake (0.8.7, 0.8.5)thor (0.13.6)
guru/code$ ruby test_load_path_lock.rb test_load_path_lock.rb:6:in `require': no such file to load -- thor (LoadError) from test_load_path_lock.rb:6
Lock no $LOAD_PATH
Hugo Baraúna @hugobaraunablog.plataformatec.com
# Gemfilegem "rake"
# test_load_path_lock.rbrequire "rubygems"require "bundler"Bundler.setuprequire "rake"require "thor"
guru/code$ gem listrake (0.8.7, 0.8.5)thor (0.13.6)
guru/code$ ruby test_load_path_lock.rb test_load_path_lock.rb:6:in `require': no such file to load -- thor (LoadError) from test_load_path_lock.rb:6
Lock no $LOAD_PATH
Hugo Baraúna @hugobaraunablog.plataformatec.com
Hugo Baraúna @hugobaraunablog.plataformatec.com
BundlerRouterActionMailerActiveModelRespondersARelUnobtrusive JavascriptXSS Protection
Hugo Baraúna @hugobaraunablog.plataformatec.com
Router
Hugo Baraúna @hugobaraunablog.plataformatec.com
Nova API
Hugo Baraúna @hugobaraunablog.plataformatec.com
Rotas rootRails 2.3
Rails 3
map.root :controller => "welcome"
root :to => "welcome#index"
Hugo Baraúna @hugobaraunablog.plataformatec.com
Rotas comumRails 2.3
Rails 3
map.connect "products/:id", controller=> "catalog", :action => "view"
match 'products/:id' => 'catalog#view'
Hugo Baraúna @hugobaraunablog.plataformatec.com
Named routesRails 2.3
Rails 3
map.purchase "products/:id/purchase", :controller => "catalog", :action => "purchase"
match "products/:id/purchase" => 'catalog#purchase', :as => :purchase
Hugo Baraúna @hugobaraunablog.plataformatec.com
Resources com member e collection
Rails 2.3
Rails 3
map.resources :products, :member => { :short => :get, :toggle => :post }, :collection => { :sold => :get }
resources :products do member do get :short post :toggle end
collection do get :sold endend
Hugo Baraúna @hugobaraunablog.plataformatec.com
Router and Rack FTW!
Hugo Baraúna @hugobaraunablog.plataformatec.com
Rack FTW!
Hugo Baraúna @hugobaraunablog.plataformatec.com
Rack FTW!
match "posts/:echo" => "posts#show"
Hugo Baraúna @hugobaraunablog.plataformatec.com
Rack FTW!
match "posts/:echo" => "posts#show"
match "posts/:echo" => PostsController.action(:show)
uma Rack App!
Hugo Baraúna @hugobaraunablog.plataformatec.com
Rack FTW!
match "posts/:echo" => "posts#show"
match "posts/:echo" => PostsController.action(:show)
match "posts/:echo" => lambda { |env| [ 200, {“Content-Type” => “plain/text”}, ["Echo!"] ] }
uma Rack App!
Hugo Baraúna @hugobaraunablog.plataformatec.com
Rack FTW!
match "posts/:echo" => "posts#show"
match "posts/:echo" => PostsController.action(:show)
match "posts/:echo" => MySinatraBlog
match "posts/:echo" => lambda { |env| [ 200, {“Content-Type” => “plain/text”}, ["Echo!"] ] }
uma Rack App!
Hugo Baraúna @hugobaraunablog.plataformatec.com
BundlerRouterActionMailerActiveModelRespondersARelUnobtrusive JavascriptXSS Protection
Hugo Baraúna @hugobaraunablog.plataformatec.com
ActionMailer new API
Hugo Baraúna @hugobaraunablog.plataformatec.com
ActionMailer new API
guru/code$ ls -lp app/ controllers/ helpers/ mailers/ models/ views/
guru/code$ rails g mailer Notifier signup_notification create app/mailers/notifier.rb invoke erb create app/views/notifier create app/views/notifier/signup_notification.text.erb invoke test_unit create test/functional/notifier_test.rb
Hugo Baraúna @hugobaraunablog.plataformatec.com
ActionMailer new API
guru/code$ ls -lp app/ controllers/ helpers/ mailers/ models/ views/
guru/code$ rails g mailer Notifier signup_notification create app/mailers/notifier.rb invoke erb create app/views/notifier create app/views/notifier/signup_notification.text.erb invoke test_unit create test/functional/notifier_test.rb
mailers com diretório próprio
Hugo Baraúna @hugobaraunablog.plataformatec.com
class Notifier < ActionMailer::Base default :from => "[email protected]" def signup_notification(recipient) @account = recipient attachments['image.jpg'] = File.read("image.jpg") mail(:to => recipient.email) do |format| format.html format.text end endend
ActionMailer new API
Hugo Baraúna @hugobaraunablog.plataformatec.com
class Notifier < ActionMailer::Base default :from => "[email protected]" def signup_notification(recipient) @account = recipient attachments['image.jpg'] = File.read("image.jpg") mail(:to => recipient.email) do |format| format.html format.text end endend
Variáveisde
instância
ActionMailer new API
Hugo Baraúna @hugobaraunablog.plataformatec.com
class Notifier < ActionMailer::Base default :from => "[email protected]" def signup_notification(recipient) @account = recipient attachments['image.jpg'] = File.read("image.jpg") mail(:to => recipient.email) do |format| format.html format.text end endend
Variáveisde
instânciaAttachments tipo
cookies
ActionMailer new API
Hugo Baraúna @hugobaraunablog.plataformatec.com
class Notifier < ActionMailer::Base default :from => "[email protected]" def signup_notification(recipient) @account = recipient attachments['image.jpg'] = File.read("image.jpg") mail(:to => recipient.email) do |format| format.html format.text end endend
Variáveisde
instânciaAttachments tipo
cookies
mail tipo respond_to do |format|
ActionMailer new API
Hugo Baraúna @hugobaraunablog.plataformatec.com
ActionMailer ::Base ActionController ::Base
ActionController ::Metal
AbstractController ::Base
Hugo Baraúna @hugobaraunablog.plataformatec.com
BundlerRouterActionMailerActiveModelRespondersARelUnobtrusive JavascriptXSS Protection
Hugo Baraúna @hugobaraunablog.plataformatec.com
ActiveModel
Hugo Baraúna @hugobaraunablog.plataformatec.com
ActiveModel
Hugo Baraúna @hugobaraunablog.plataformatec.com
ActiveModel
• Google Summer of Code 2009:
Hugo Baraúna @hugobaraunablog.plataformatec.com
ActiveModel
• Google Summer of Code 2009:
• Extrair a lógica comum entre ActiveRecord e ActiveResource
Hugo Baraúna @hugobaraunablog.plataformatec.com
ActiveModel
• Google Summer of Code 2009:
• Extrair a lógica comum entre ActiveRecord e ActiveResource
• Hoje
Hugo Baraúna @hugobaraunablog.plataformatec.com
ActiveModel
• Google Summer of Code 2009:
• Extrair a lógica comum entre ActiveRecord e ActiveResource
• Hoje
•Desempenha papel no agnosticismo de ORM
Hugo Baraúna @hugobaraunablog.plataformatec.com
ActiveModel
• Google Summer of Code 2009:
• Extrair a lógica comum entre ActiveRecord e ActiveResource
• Hoje
•Desempenha papel no agnosticismo de ORM
• Permite a criação de models à la ActiveRecord
Hugo Baraúna @hugobaraunablog.plataformatec.com
ActiveResource::Base + ActiveModel
module ActiveResource ... class Base extend ActiveModel::Naming include CustomMethods, Observing, Validations include ActiveModel::Conversion include ActiveModel::Serializers::JSON include ActiveModel::Serializers::Xml end endend
Hugo Baraúna @hugobaraunablog.plataformatec.com
ActiveRecord::Base + ActiveModel
Base.class_eval do ... extend ActiveModel::Naming ... include ActiveModel::Conversion include Validations ... include Callbacks, ActiveModel::Observing, Timestamp endend
Hugo Baraúna @hugobaraunablog.plataformatec.com
Agnosticismo de ORM
Hugo Baraúna @hugobaraunablog.plataformatec.com
ActiveModel Rails::Railtie
Agnosticismo de ORM
Agnosticismo de ORM
Hugo Baraúna @hugobaraunablog.plataformatec.com
ActiveModel Rails::Railtie
Agnosticismo de ORM
Agnosticismo de ORM
Provê uma API para que o ActionPack possa conversar com o
ORM
Hugo Baraúna @hugobaraunablog.plataformatec.com
ActiveModel Rails::Railtie
Agnosticismo de ORM
Agnosticismo de ORM
Integração do ORM com o RailsProvê uma API para que o ActionPack possa conversar com o
ORM
Hugo Baraúna @hugobaraunablog.plataformatec.com
ActiveModel::Lint::Tests
Hugo Baraúna @hugobaraunablog.plataformatec.com
module ActiveModel module Lint module Tests
def test_to_key assert model.respond_to?(:to_key), "The model should respond to to_key" def model.persisted?() false end assert model.to_key.nil? end
def test_to_param assert model.respond_to?(:to_param), "The model should respond to to_param" def model.persisted?() false end assert model.to_param.nil? end
def test_valid? assert model.respond_to?(:valid?), "The model should respond to valid?" assert_boolean model.valid?, "valid?" end ... def test_persisted? assert model.respond_to?(:persisted?), "The model should respond to persisted?" assert_boolean model.persisted?, "persisted?" end
def test_errors_aref assert model.respond_to?(:errors), "The model should respond to errors" assert model.errors[:hello].is_a?(Array), "errors#[] should return an Array" end
def test_errors_full_messages assert model.respond_to?(:errors), "The model should respond to errors" assert model.errors.full_messages.is_a?(Array), "errors#full_messages should return an Array" end
end endend
Hugo Baraúna @hugobaraunablog.plataformatec.com
def test_to_param assert model.respond_to?(:to_param), "The model should respond to to_param" def model.persisted?() false end assert model.to_param.nil? end
def test_valid? assert model.respond_to?(:valid?), "The model should respond to valid?" assert_boolean model.valid?, "valid?" end ...
def test_errors_aref assert model.respond_to?(:errors), "The model should respond to errors" assert model.errors[:hello].is_a?(Array), "errors#[] should return an Array" end
Hugo Baraúna @hugobaraunablog.plataformatec.com
ActiveRecord-like
http://github.com/plataformatec/mail_form
Ótimo exemplo de uso do ActiveModel
Hugo Baraúna @hugobaraunablog.plataformatec.com
ActiveModel
Hugo Baraúna @hugobaraunablog.plataformatec.com
BundlerRouterActionMailerActiveModelRespondersARelUnobtrusive JavascriptXSS Protection
Hugo Baraúna @hugobaraunablog.plataformatec.com
Responders
Hugo Baraúna @hugobaraunablog.plataformatec.com
RAILS 2.3
def index @users = User.all respond_to do |format| format.html # index.html.erb format.xml { render :xml => @users } endend
Hugo Baraúna @hugobaraunablog.plataformatec.com
RAILS 2.3
def index @users = User.all respond_to do |format| format.html # index.html.erb format.xml { render :xml => @users } endend
Hugo Baraúna @hugobaraunablog.plataformatec.com
RAILS 3.0
respond_to :html, :xml
def index @users = User.all respond_with(@users)end
Hugo Baraúna @hugobaraunablog.plataformatec.com
RAILS 3.0
respond_to :html, :xml
def index @users = User.all respond_with(@users)end
Hugo Baraúna @hugobaraunablog.plataformatec.com
Navigational API
GET
POST
PUT
DELETE
Hugo Baraúna @hugobaraunablog.plataformatec.com
Navigational API
GET
POST
PUT
DELETE
Hugo Baraúna @hugobaraunablog.plataformatec.com
Navigational API
GET
POST
PUT
DELETE
Hugo Baraúna @hugobaraunablog.plataformatec.com
respond_to :html, :xml
def index @users = User.all respond_with(@users)end
Hugo Baraúna @hugobaraunablog.plataformatec.com
Navigational API
GET render template render collection.to_format
POST
PUT
DELETE
Hugo Baraúna @hugobaraunablog.plataformatec.com
def create @user = User.new(params[:user]) respond_to do |format| if @user.save format.html { redirect_to @user, :notice => 'User was successfully created' } format.xml { render :xml => @user, :status => :created, :location => @user } else format.html { render :action => "new" } format.xml { render :xml => @user.errors, :status => :unprocessable_entity } end endend
RAILS 2.3
Hugo Baraúna @hugobaraunablog.plataformatec.com
RAILS 3.0
def create @user = User.new(params[:user]) flash[:notice] = 'User was successfully created' if @user.save respond_with(@user)end
Hugo Baraúna @hugobaraunablog.plataformatec.com
Navigational API
GETGET render template render collection.to_format
POSTSuccess redirect_to resource render
resource.to_formatPOST
Failure render :new render resource.errors
PUTPUT
DELETEDELETE
Hugo Baraúna @hugobaraunablog.plataformatec.com
Navigational API
GETGET render template render collection.to_format
POSTSuccess redirect_to resource render
resource.to_formatPOST
Failure render :new render resource.errors
PUTSuccess redirect_to resource head :ok
PUTFailure render :edit render resource.errors
DELETEDELETE redirect_to collection head :ok
Hugo Baraúna @hugobaraunablog.plataformatec.com
respond_with(@users)
ActionController ::Responder
Hugo Baraúna @hugobaraunablog.plataformatec.com
respond_with(@users)
Navigational API
GETGET render template render collection.to_format
POST
Success redirect_to resource render resource.to_format
POSTFailure render :new render resource.errors
PUT
Success redirect_to resource head :ok
PUTFailure render :edit render resource.errors
DELETEDELETE redirect_to collection head :ok
table.to_code
ActionController ::Responder
Hugo Baraúna @hugobaraunablog.plataformatec.com
Responders Customizados
Hugo Baraúna @hugobaraunablog.plataformatec.com
github.com/plataformatec/responders
Hugo Baraúna @hugobaraunablog.plataformatec.com
github.com/plataformatec/responders
Hugo Baraúna @hugobaraunablog.plataformatec.com
github.com/plataformatec/responders
FlashResponder: seta o flash baseado na action do controller e no status do recurso
Hugo Baraúna @hugobaraunablog.plataformatec.com
github.com/plataformatec/responders
FlashResponder: seta o flash baseado na action do controller e no status do recurso
HttpCacheResponder: automaticamente adiciona o cabeçalho HTTP Last-Modified para requests de API format
Hugo Baraúna @hugobaraunablog.plataformatec.com
# lib/application_responder.rbclass ApplicationResponder < ActionController::Responder include Responders::FlashResponder include Responders::HttpCacheResponderend
CONFIGURANDO O RESPONDERS
Hugo Baraúna @hugobaraunablog.plataformatec.com
# lib/application_responder.rbclass ApplicationResponder < ActionController::Responder include Responders::FlashResponder include Responders::HttpCacheResponderend
CONFIGURANDO O RESPONDERS
# app/controllers/application_controller.rbclass ApplicationController < ActionController::Base self.responder = ApplicationResponder respond_to :html
protect_from_forgery layout 'application'end
Hugo Baraúna @hugobaraunablog.plataformatec.com
SEM O RESPONDERS
# app/controllers/users_controller.rbdef create @user = User.new(params[:user]) flash[:notice] = 'User was successfully created' if @user.save respond_with(@user)end
Hugo Baraúna @hugobaraunablog.plataformatec.com
SEM O RESPONDERS
# app/controllers/users_controller.rbdef create @user = User.new(params[:user]) flash[:notice] = 'User was successfully created' if @user.save respond_with(@user)end
O FlashResponder vai fazer isso por mim
Hugo Baraúna @hugobaraunablog.plataformatec.com
COM O RESPONDERS
# app/controllers/users_controller.rbdef create @user = User.new(params[:user]) @user.save respond_with(@user)end
# config/locales/en.ymlen: flash: users: create: success: “User was successfully created”
Hugo Baraúna @hugobaraunablog.plataformatec.com
Responders
Hugo Baraúna @hugobaraunablog.plataformatec.com
BundlerRouterActionMailerActiveModelRespondersARelUnobtrusive JavascriptXSS Protection
Hugo Baraúna @hugobaraunablog.plataformatec.com
ARel
Hugo Baraúna @hugobaraunablog.plataformatec.com
Lazy loading# Rails 2.3Job.find(:all, :conditions => {:published => true})
# Rails 3Job.where(:published => true)
Faz um query no DB imediatamente e retorna um array de Jobs
Não faz query no DB, retorna um ActiveRecord::Relation
Hugo Baraúna @hugobaraunablog.plataformatec.com
Onde a query roda?# app/controllers/jobs_controller.rbclass JobsController < ApplicationController def index @jobs = Jobs.where(:published => true).order("created_at DESC") endend
# app/views/jobs/index.html.erb<% cache do %> <% @jobs.each do |job| %> ... <% end %><% end %>
Hugo Baraúna @hugobaraunablog.plataformatec.com
Onde a query roda?# app/controllers/jobs_controller.rbclass JobsController < ApplicationController def index @jobs = Jobs.where(:published => true).order("created_at DESC") endend
# app/views/jobs/index.html.erb<% cache do %> <% @jobs.each do |job| %> ... <% end %><% end %>
Não realiza query no DB
Hugo Baraúna @hugobaraunablog.plataformatec.com
Onde a query roda?# app/controllers/jobs_controller.rbclass JobsController < ApplicationController def index @jobs = Jobs.where(:published => true).order("created_at DESC") endend
# app/views/jobs/index.html.erb<% cache do %> <% @jobs.each do |job| %> ... <% end %><% end %>
Só aqui que será feito a query no DB
Não realiza query no DB
Hugo Baraúna @hugobaraunablog.plataformatec.com
Onde a query roda?# app/controllers/jobs_controller.rbclass JobsController < ApplicationController def index @jobs = Jobs.where(:published => true).order("created_at DESC") endend
# app/views/jobs/index.html.erb<% cache do %> <% @jobs.each do |job| %> ... <% end %><% end %>
Só aqui que será feito a query no DB
Não realiza query no DB
Se estiver cacheado, não faz a query no controller a toa
Hugo Baraúna @hugobaraunablog.plataformatec.com
Chainability: it “quacks” like named_scope
Job.where(:title => 'Rails Developer')Job.order('created_at DESC').limit(20).includes(:company)
cars = Car.where(:colour => 'black')black_fancy_cars = cars.order('cars.price DESC').limit(10)black_cheap_cart = cars.order('cars.price ASC').limit(10)
Hugo Baraúna @hugobaraunablog.plataformatec.com
Chainability: it “quacks” like named_scope
Job.where(:title => 'Rails Developer')Job.order('created_at DESC').limit(20).includes(:company)
cars = Car.where(:colour => 'black')black_fancy_cars = cars.order('cars.price DESC').limit(10)black_cheap_cart = cars.order('cars.price ASC').limit(10)
ActiveRecord::Relation
Hugo Baraúna @hugobaraunablog.plataformatec.com
Chainability: it “quacks” like named_scope
Job.where(:title => 'Rails Developer')Job.order('created_at DESC').limit(20).includes(:company)
cars = Car.where(:colour => 'black')black_fancy_cars = cars.order('cars.price DESC').limit(10)black_cheap_cart = cars.order('cars.price ASC').limit(10)
ActiveRecord::Relation
Reaproveitar uma Relation e encadear mais finders
Hugo Baraúna @hugobaraunablog.plataformatec.com
ARel
Hugo Baraúna @hugobaraunablog.plataformatec.com
BundlerRouterActionMailerActiveModelRespondersARelUnobtrusive JavascriptXSS Protection
Hugo Baraúna @hugobaraunablog.plataformatec.com
Unobtrusive Javascript
Hugo Baraúna @hugobaraunablog.plataformatec.com
remote_form_for(@post)
Unobtrusive Javascript: Rails 2.3
link_to 'Destroy', post, :confirm => 'Are you sure?',:method => :delete
Hugo Baraúna @hugobaraunablog.plataformatec.com
remote_form_for(@post)
Unobtrusive Javascript: Rails 2.3
<form action="/posts" class="new_post" id="new_post" method="post" onsubmit="new Ajax.Request('/posts', {asynchronous:true, evalScripts:true, parameters:Form.serialize(this)}); return false;">
link_to 'Destroy', post, :confirm => 'Are you sure?',:method => :delete
Hugo Baraúna @hugobaraunablog.plataformatec.com
remote_form_for(@post)
Unobtrusive Javascript: Rails 2.3
<form action="/posts" class="new_post" id="new_post" method="post" onsubmit="new Ajax.Request('/posts', {asynchronous:true, evalScripts:true, parameters:Form.serialize(this)}); return false;">
link_to 'Destroy', post, :confirm => 'Are you sure?',:method => :delete<a href="/posts/1" onclick="if (confirm('Are you sure?')) { var f = document.createElement('form'); f.style.display = 'none'; this.parentNode.appendChild(f); f.method = 'POST'; f.action = this.href;var m = document.createElement('input'); m.setAttribute('type', 'hidden'); m.setAttribute('name', '_method'); m.setAttribute('value', 'delete'); f.appendChild(m);var s = document.createElement('input'); s.setAttribute('type', 'hidden'); s.setAttribute('name', 'authenticity_token'); s.setAttribute('value', 'LM2fEF6HuRWdYUZdEumWlemhI6iDPH97pqWhO4jEpiU='); f.appendChild(s);f.submit(); };return false;">Destroy</a>
Hugo Baraúna @hugobaraunablog.plataformatec.com
Unobtrusive Javascript: Rails 3# Rails 2.3remote_form_for(@post)<form action="/posts" class="new_post" id="new_post" method="post" onsubmit="new Ajax.Request('/posts', {asynchronous:true, evalScripts:true, parameters:Form.serialize(this)}); return false;">
Hugo Baraúna @hugobaraunablog.plataformatec.com
Unobtrusive Javascript: Rails 3# Rails 2.3remote_form_for(@post)<form action="/posts" class="new_post" id="new_post" method="post" onsubmit="new Ajax.Request('/posts', {asynchronous:true, evalScripts:true, parameters:Form.serialize(this)}); return false;">
# Rails 3form_for(@posts, :remote => true)
<form action="/posts" class="new_post" data-remote="true" id="new_post" method="post">
Hugo Baraúna @hugobaraunablog.plataformatec.com
Unobtrusive Javascript: Rails 3# Rails 2.3remote_form_for(@post)<form action="/posts" class="new_post" id="new_post" method="post" onsubmit="new Ajax.Request('/posts', {asynchronous:true, evalScripts:true, parameters:Form.serialize(this)}); return false;">
# Rails 3form_for(@posts, :remote => true)
<form action="/posts" class="new_post" data-remote="true" id="new_post" method="post">
Hugo Baraúna @hugobaraunablog.plataformatec.com
Unobtrusive Javascript: Rails 3# Rails 2.3link_to 'Destroy', post, :confirm => 'Are you sure?',:method => :delete<a href="/posts/1" onclick="if (confirm('Are you sure?')) { var f = document.createElement('form'); f.style.display = 'none'; this.parentNode.appendChild(f); f.method = 'POST'; f.action = this.href;var m = document.createElement('input'); m.setAttribute('type', 'hidden'); m.setAttribute('name', '_method'); m.setAttribute('value', 'delete'); f.appendChild(m);var s = document.createElement('input'); s.setAttribute('type', 'hidden'); s.setAttribute('name', 'authenticity_token'); s.setAttribute('value', 'LM2fEF6HuRWdYUZdEumWlemhI6iDPH97pqWhO4jEpiU='); f.appendChild(s);f.submit(); };return false;">Destroy</a>
Hugo Baraúna @hugobaraunablog.plataformatec.com
Unobtrusive Javascript: Rails 3# Rails 2.3link_to 'Destroy', post, :confirm => 'Are you sure?',:method => :delete<a href="/posts/1" onclick="if (confirm('Are you sure?')) { var f = document.createElement('form'); f.style.display = 'none'; this.parentNode.appendChild(f); f.method = 'POST'; f.action = this.href;var m = document.createElement('input'); m.setAttribute('type', 'hidden'); m.setAttribute('name', '_method'); m.setAttribute('value', 'delete'); f.appendChild(m);var s = document.createElement('input'); s.setAttribute('type', 'hidden'); s.setAttribute('name', 'authenticity_token'); s.setAttribute('value', 'LM2fEF6HuRWdYUZdEumWlemhI6iDPH97pqWhO4jEpiU='); f.appendChild(s);f.submit(); };return false;">Destroy</a>
# Rails 3link_to 'Destroy', post, :confirm => 'Are you sure?', :method => :delete
<a href="/posts/1" data-confirm="Are you sure?" data-method="delete" rel="nofollow">Destroy</a>
Hugo Baraúna @hugobaraunablog.plataformatec.com
Unobtrusive Javascript: Rails 3# Rails 2.3link_to 'Destroy', post, :confirm => 'Are you sure?',:method => :delete<a href="/posts/1" onclick="if (confirm('Are you sure?')) { var f = document.createElement('form'); f.style.display = 'none'; this.parentNode.appendChild(f); f.method = 'POST'; f.action = this.href;var m = document.createElement('input'); m.setAttribute('type', 'hidden'); m.setAttribute('name', '_method'); m.setAttribute('value', 'delete'); f.appendChild(m);var s = document.createElement('input'); s.setAttribute('type', 'hidden'); s.setAttribute('name', 'authenticity_token'); s.setAttribute('value', 'LM2fEF6HuRWdYUZdEumWlemhI6iDPH97pqWhO4jEpiU='); f.appendChild(s);f.submit(); };return false;">Destroy</a>
# Rails 3link_to 'Destroy', post, :confirm => 'Are you sure?', :method => :delete
<a href="/posts/1" data-confirm="Are you sure?" data-method="delete" rel="nofollow">Destroy</a>
Hugo Baraúna @hugobaraunablog.plataformatec.com
JS Driver
Markup com HTML 5 custom data attributes
JS Driver
JS Framework
Hugo Baraúna @hugobaraunablog.plataformatec.com
JS Driver// public/javascripts/rails.jsdocument.observe("dom:loaded", function() { function handleRemote(element) { var method, url, params;
if (element.tagName.toLowerCase() === 'form') { method = element.readAttribute('method') || 'post'; url = element.readAttribute('action'); params = element.serialize(true); } else { method = element.readAttribute('data-method') || 'get'; url = element.readAttribute('href'); params = {}; }
var event = element.fire("ajax:before"); if (event.stopped) return false;
new Ajax.Request(url, { method: method, parameters: params, asynchronous: true, evalScripts: true,
onLoading: function(request) { element.fire("ajax:loading", {request: request}); }, onLoaded: function(request) { element.fire("ajax:loaded", {request: request}); }, onInteractive: function(request) { element.fire("ajax:interactive", {request: request}); }, onComplete: function(request) { element.fire("ajax:complete", {request: request}); }, onSuccess: function(request) { element.fire("ajax:success", {request: request}); }, onFailure: function(request) { element.fire("ajax:failure", {request: request}); } });
element.fire("ajax:after"); } ...
Apenas 119 linhas!
Hugo Baraúna @hugobaraunablog.plataformatec.com
JS para todos os gostos
• Prototype: default
• jQuery: http://github.com/rails/jquery-ujs
•MooTools: http://mootools.net/forge/p/rails_3_driver
• Você pode fazer o seu!
Hugo Baraúna @hugobaraunablog.plataformatec.com
Javascript no Rails 3
Hugo Baraúna @hugobaraunablog.plataformatec.com
HTML 5 custom data attributes JS driver para cada framework
Agnosticismo de Javascript
Javascript no Rails 3
Hugo Baraúna @hugobaraunablog.plataformatec.com
BundlerRouterActionMailerActiveModelRespondersARelUnobtrusive JavascriptXSS Protection
Hugo Baraúna @hugobaraunablog.plataformatec.com
XSS Protection
Hugo Baraúna @hugobaraunablog.plataformatec.com
XSS protection
<%= @job.title %> <%= h @job.title %>
Rails 2.3: unsafe por default
safeunsafe
<%= @job.title %> <%= raw @job.title %>
Rails 3: safe por default
safe unsafe
Hugo Baraúna @hugobaraunablog.plataformatec.com
XSS protection
<%= @job.title %> <%= h @job.title %>
Rails 2.3: unsafe por default
safeunsafe
<%= @job.title %> <%= raw @job.title %>
Rails 3: safe por default
safe unsafe
Hugo Baraúna @hugobaraunablog.plataformatec.com
XSS protection
<%= @job.title %> <%= h @job.title %>
Rails 2.3: unsafe por default
safeunsafe
<%= @job.title %> <%= raw @job.title %>
Rails 3: safe por default
safe unsafe
Hugo Baraúna @hugobaraunablog.plataformatec.com
ActiveSupport::SafeBuffer
guru/code$ rails console> a ="maybe dangerous" => "maybe dangerous" > a.html_safe? => false > b = a.html_safe => "maybe dangerous" > b.html_safe? => true > b.class => ActiveSupport::SafeBuffer
Hugo Baraúna @hugobaraunablog.plataformatec.com
Helpers que retornam HTML
module ApplicationHelper def strong(content) "<strong>#{h content}</string>".html_safe endend
Hugo Baraúna @hugobaraunablog.plataformatec.com
Helpers que retornam HTML
module ApplicationHelper def strong(content) "<strong>#{h content}</string>".html_safe endend
Dicas:1. Certificar-se de que todo input está sendo escapado
Hugo Baraúna @hugobaraunablog.plataformatec.com
Helpers que retornam HTML
module ApplicationHelper def strong(content) "<strong>#{h content}</string>".html_safe endend
Dicas:1. Certificar-se de que todo input está sendo escapado
2. Chamar html_safe no output
Hugo Baraúna @hugobaraunablog.plataformatec.com
http://github.com/plataformatec
Tem muito mais aqui!
Hugo Baraúna @hugobaraunablog.plataformatec.com
blog twitterID
http://github.com/plataformatec
Tem muito mais aqui!