Um roadmap do Framework Ruby on Rails, do Rails 1 ao Rails 4 - DevDay 2013
-
Upload
joao-lucas-santana -
Category
Education
-
view
1.504 -
download
2
description
Transcript of Um roadmap do Framework Ruby on Rails, do Rails 1 ao Rails 4 - DevDay 2013
Um roadmap do Framework Ruby on Rails
do Rails 1 ao Rails 4
João Lucas Pereira de Santana
#devday2013@jlucasps
Apresentação
João Lucas Pereira de Santana
twitter | github | fb | gtalk: @jlucasps
Ciência da Computação pela UFLA
Desenvolvedor Ruby, Java, JavaScript
Instrutor Ruby on Rails
#devday2013@jlucasps
Agenda
➔ Rails Full Stack - Request/Responder
➔ Primeira versão
◆ Active Support, Active Record, Action Pack, Action
Mailer
➔ Rails 2
➔ Rails 3
➔ Rails 4
#devday2013@jlucasps
Rails Full Stack
➔ Origem
◆ David Heinemeier Hansson
#devday2013@jlucasps
Rails Full Stack
➔ Rails Core Team
Jeremy Kemper Michael Koziarski Yehuda Katz José Valim
Santiago Pastorino Aaron Patterson Xavier Noria Jon Leighton
Rafael França Andrew White Guillermo Iguaran Carlos Antonio
➔ Framework MVC para desenvolvimento Web
#devday2013@jlucasps
Rails Full Stack
TestesTestes
Testes
Model View
ControllerHTTP/SSL
Routes
Helpers
Middleware
Responders
Renders
Session
Logs
Associations
Validations
Queries
Callbacks
Connections
Migrations
Assets
Helpers
Builders
Templates
Partials
#devday2013@jlucasps
Rails Full Stack
Model View
Controller
Web Server
App Server
Rai
ls
request
response
#devday2013@jlucasps
Rails Full Stack
Model View
Controller
Web Server
App Server
Rai
ls
REQUEST: GET http://myapp.com/users/2/lists
ACCEPTED: passado para o App Server
Request passado para o Rails
#devday2013@jlucasps
Rails Full Stack
Model View
Controller
Rai
ls
Router
#devday2013@jlucasps
Rails Full Stack
Router
user_lists GET /users/:user_id/lists(.:format) lists#index
Controller e Action selecionadas:
GET /users/2/lists
CONTROLLER: "lists"
ACTION: "index"
NOME DA ROTA: "user_lists"
#devday2013@jlucasps
Rails Full Stack
Model View
Controller
Rai
ls
Router
Controller
ListsController
Model View
index new create
update destroy ........
GET /users/2/listsCONTROLLER: "lists"ACTION: "index"
#devday2013@jlucasps
Rails Full Stack
Model
@user = User.find(params[:user_id])@lists = List.find_all_by_user_id(params[:user_id])
ListsControllerindex new create
update destroy ........
UserModel
ListModel
ActiveRecord
ActiveRecord
Banco de dados
tabela 'users'
tabela 'lists'
#devday2013@jlucasps
Rails Full Stack
REQUEST: GET http://myapp.com/users/2/lists
ACCEPTED: passado para o App Server
REQUEST passado para o Rails
PATH e METHOD mapeados para CONTROLLER e ACTION
CONTROLLER recupera informações dos MODELS para suprir a VIEW
Model View
Controller
Web Server
App Server
Rai
ls
Router
action action action
#devday2013@jlucasps
Rails Full Stack
View
ListsController
index
update
View
app/views/lists/index.html.erb
edit
..........
app/views/lists/update.html.erb
@vars
.html
@vars
.html
Request HeadersAccept: text/html, application/xhtml+xml
#devday2013@jlucasps
Rails Full Stack
HTTP Response
#devday2013@jlucasps
Rails Full Stack
REQUEST: GET http://myapp.com/users/2/lists
ACCEPTED: passado para o App Server
REQUEST passado para o Rails
PATH e METHOD mapeados para CONTROLLER e ACTION
CONTROLLER recupera informações dos MODELS para suprir a VIEW
Model View
Controller
Web Server
App Server
Rai
ls
Router
action action action
VIEW cria a resposta para o RESPONSE BODY
#devday2013@jlucasps
Rails Full Stack
Model View
Controller
Web Server
App Server
Rai
ls
Router
action action action
VIEW cria a resposta para o RESPONSE BODY
RESPONSE volta através do middleware stack
RESPONSE é retornada para o browser
RESPONSE recebida :-)
#devday2013@jlucasps
Rails Full Stack
Response
➔ Inflectors
#devday2013@jlucasps
rails-0.10.0
SingularToPlural = { "search" => "searches", "category" => "categories", "wife" => "wives", "series" => "series" } CamelToUnderscore = { "Product" => "product", "SpecialGuest" => "special_guest" } CamelWithModuleToUnderscoreWithSlash = { "Admin::Product" => "admin/product", "UsersSection::CommissionDepartment" => "users_section/commission_department" } ClassNameToForeignKeyWithUnderscore = { "Person" => "person_id", "MyApplication::Billing::Account" => "account_id" } ClassNameToTableName = { "PrimarySpokesman" => "primary_spokesmen", "NodeChild" => "node_children" }
➔ Breakpoints
#devday2013@jlucasps
rails-0.10.0
[0, 9] in /media/truecrypt1/rails4chat/app/controllers/pages_controller.rb 1 class PagesController < ApplicationController 2 3 def index 4 debugger=> 5 @messages = Message.limit(20) 6 end 7 8 end (rdb:1) params {"controller"=>"pages", "action"=>"index"} (rdb:1)
➔ active_support core_ext
◆ Time
#devday2013@jlucasps
rails-0.10.0
# Calculations
assert_equal Time.local(2006,2,22,15,15,10), Time.local(2005,2,22,15,15,10).change(:year
=> 2006)
assert_equal Time.local(2005,2,22,10,10,9), Time.local(2005,2,22,10,10,10).ago(1)
assert_equal Time.local(2005,2,20,10,10,10), Time.local(2005,2,22,10,10,10).ago(86400*2)
assert_equal Time.local(2005,1,31), Time.local(2005,2,4,10,10,10).beginning_of_week
assert_equal Time.local(2005,2,4,0,0,0), Time.local(2005,2,4,10,10,10).beginning_of_day
# Conversions
assert_equal "February 21, 2005 17:44", Time.local(2005, 2, 21, 17, 44, 30).to_s(:long)
assert_equal Date.new(2005, 2, 21), Time.local(2005, 2, 21, 17, 44, 30).to_date
➔ active_support core_ext
◆ Numeric
#devday2013@jlucasps
rails-0.10.0
# byte calculations
1024.kilobytes => 1.megabyte
1.kilobyte ** 4 => 1.terabyte
time calculations
1.minute => 60
1.hour + 15.minutes => 4500
2.days + 4.hours + 30.minutes => 189000
➔ active_support core_ext
◆ Hash
#devday2013@jlucasps
rails-0.10.0
# hash
# stringify_keys, symbolize_keys e indifferent_access
strings = { 'a' => 1, 'b' => 2 }
symbols = { :a => 1, :b => 2 }
mixed = { :a => 1, 'b' => 2 }
➔ active_support core_ext
◆ Date
#devday2013@jlucasps
rails-0.10.0
# Getting dates in different convenient string representations and other
objects
assert_equal "21 Feb", Date.new(2005, 2, 21).to_s(:short)
assert_equal "February 21, 2005", Date.new(2005, 2, 21).to_s(:long)
# to_time
assert_equal Time.local(2005, 2, 21), Date.new(2005, 2, 21).to_time
# to_date
assert_equal Date.new(2005, 2, 21), Date.new(2005, 2, 21).to_date
➔ active_record
◆ connections:
● db2, mysql, oracle, postgresql, sqlite, sqlite3,
sqlserver
◆ mapping:
#devday2013@jlucasps
rails-0.10.0
table "products"
class Product < ActiveRecord::Base
end
➔ active_record
◆ associations:
#devday2013@jlucasps
rails-0.10.0
class Firm < ActiveRecord::Base
has_many :clients
has_one :account
belongs_to :conglomorate
has_and_belongs_to_many :investors
end
# natural assignments:
apple.account = citibank
assert_equal apple.id, citibank.firm_id
➔ active_record
◆ validations:
#devday2013@jlucasps
rails-0.10.0
# Validation rules that can differ for new or existing objects
class Account < ActiveRecord::Base
validates_presence_of :subdomain, :name, :email_address, :
password
validates_uniqueness_of :subdomain
validates_acceptance_of :terms_of_service, :on => :create
validates_confirmation_of :password, :email_address, :on => :
create
end
➔ active_record
◆ callbacks:
#devday2013@jlucasps
rails-0.10.0
# Callbacks as methods or queues on the entire lifecycle
# (instantiation, saving, destroying, validating, etc).
:after_find, :after_initialize, :before_validation
:before_validation_on_update, :after_validation
:after_validation_on_update, :before_save
:before_update, :after_update, :after_save
:before_destroy, :after_destroy
➔ active_record
◆ find and dynamic methods
#devday2013@jlucasps
rails-0.10.0
# findsFirm.find(1, 2)Company.find_first "name = 'Next Angle'"Firm.find_by_sql("SELECT * FROM companies WHERE id = 1").firstTopic.find(1, :conditions => "approved = 1")Topic.find_by_title("The First Topic")Topic.find_by_title_and_author_name("The First Topic", "David")Topic.find_all_by_content("Have a nice day") # dynamic methodsnext_angle.clients.find(2) next_angle.clients.empty?next_angle.clients.size
➔ action_pack
◆ action_controller:
#devday2013@jlucasps
rails-0.10.0
BlogController < ActionController::Base
def show
@customer = find_customer
end
private
def find_customer() Customer.find(@params["id"]) end
end
➔ action_pack
◆ filters:
#devday2013@jlucasps
rails-0.10.0
class WeblogController < ActionController::Base
before_filter :authenticate, :cache, :audit
after_filter { |c| c.response.body = GZip::compress(c.response.body) }
end
➔ action_pack
◆ layouts:
#devday2013@jlucasps
rails-0.10.0
class WeblogController < ActionController::Base
layout "weblog_layout"
def hello_world
end
end
➔ action_pack
◆ scaffold:
#devday2013@jlucasps
rails-0.10.0
require 'account' # must be an Active Record class
class AccountController < ActionController::Base
scaffold :account
end
# templates: list, show, destroy, new, create, edit, update
➔ action_pack
◆ advanced redirection
#devday2013@jlucasps
rails-0.10.0
# Advanced redirection that makes pretty urls easy:
RewriteRule ^/library/books/([A-Z]+)([0-9]+)/([-_a-zA-Z0-9]+)$ \
/books_controller.cgi?action=$3&type=$1&code=$2 [QSA] [L]
# Accessing /library/books/ISBN/0743536703/show calls BooksController#show
➔ action_pack
◆ action view:
#devday2013@jlucasps
rails-0.10.0
<!-- Embedded Ruby for templates: -->
<% for post in @posts %>
Title: <%= post.title %>
<% end %>
<!-- Helpers for forms, dates, action links, and text: -->
<%= text_field "post", "title", "size" => 30 %>
<%= html_date_select(Date.today) %>
<%= link_to "New post", :controller => "post", :action => "new" %>
<%= truncate(post.title, 25) %>
➔ action_pack
◆ action view:
#devday2013@jlucasps
rails-0.10.0
<!-- Form building for Active Record model objects: -->
<%= form "post" %>
<!-- This form generates a @params["post"] array that can be used directly in a
save action
<!-- Rendering shared partials: -->
<%= render_partial "advertisement/ad", ad %>
➔ action_mailer
#devday2013@jlucasps
rails-0.10.0
def signed_up(recipient)
@recipients = recipient
@subject = "[Signed up] Welcome #{recipient}"
@from = "[email protected]"
@sent_on = Time.local(2004, 12, 12)
@body["recipient"] = recipient
end
ApplicationMailer.deliver_signed_up("[email protected]") # sends the
➔ active_support
◆ string to date and time:
#devday2013@jlucasps
rails-0.11.0
assert_equal Time.utc(2005, 2, 27, 23, 50), "2005-02-27 23:50".to_time
assert_equal Date.new(2005, 2, 27), "2005-02-27".to_date
➔ action_pack
◆ ajax
➔ action_mailer
◆ incoming mails
➔ Eager associations
➔ new Base.find API
➔ more Ajax!
#devday2013@jlucasps
rails-0.12.0
# Turning N+1 queries into 1for post in Post.find(:all, :include => [ :author, :comments ]) puts "Post: " + post.title puts "Written by: " + post.author.name puts "Last comment on: " + post.comments.first.created_onend Person.find(1, :conditions =>"administrator = 1", :order =>"created_on DESC")Person.find(1, 5, 6, :conditions =>"administrator = 1", :order =>"created_on DESC")Person.find(:first, :order =>"created_on DESC", :offset => 5)Person.find(:all, :conditions => [ "category IN (?)", categories], :limit => 50)Person.find(:all, :offset => 10, :limit => 10)
➔ script.aculo.us
➔ ajax
#devday2013@jlucasps
rails-0.13.0
# remote link:
link_to_remote(
"test",
:url => { :action =>"faulty" },
:update => { :success =>"good", :failure =>"bad" },
403 =>"alert('Forbidden- got ya!')",
404 =>"alert('Nothing there...?')",
:failure =>"alert('Unkown error ' + request.status)"
)
➔ Migrations for PostgreSQL and MySQL
➔ Rendering: One method to bind them all
➔ Named routes
#devday2013@jlucasps
rails-0.13.0
map.home '', :controller => 'main', :action => 'start'redirect_to :controller => 'main', :action => 'start'# above route is now redirect_to :home_url
➔ Coditional validationsvalidates_numericality_of :income, :if => :employed?
validates_presence_of :username, :if => Proc.new { |user| user.signup_step
> 1 }
➔ RJS: JavaScript written in Ruby
➔ Polymorphic associations
#devday2013@jlucasps
rails-1.1.0
class Address < ActiveRecord::Base
belongs_to :addressable, :polymorphic => true
end
class Person < ActiveRecord::Base
has_one :address, :as => :addressable
end
class Company < ActiveRecord::Base
has_one :address, :as => :addressable
end
➔ calculations:
◆ sum, average, count, max
➔ Eager loading
#devday2013@jlucasps
rails-1.1.0
# Single database query:
companies = Company.find(:all, :include => { :groups => { :members=> { :
favorites } } })
# Just 1 database query for all of this:
authors = Author.find(:all, :include => [ { :posts => :comments }, :
categorizations ])
authors[0].posts[0].comments[0].body # => "Rock on Rails!"
authors[0].categorizations[0].name # => "Less software"
➔ respond_to e format
#devday2013@jlucasps
rails-1.2
class WeblogController < ActionController::Base
def index
@posts = Post.find :all
respond_to do |format|
format.html
format.xml { render :xml => @posts.to_xml }
format.rss { render :action => “feed.rxml” }
end
end
end
GET /weblog # returns HTML from browser Accept header
GET /weblog.xml # returns the XML
GET /weblog.rss # returns the RSS
➔ action_pack:
◆ resources e collection resources
◆ multiview (show.html.erb, show.js.erb)
◆ CRSF token
◆ record identification:
#devday2013@jlucasps
rails-2
# person is a Person object, which by convention will
# be mapped to person_url for lookup
redirect_to(person)
link_to(person.name, person)
form_for(person)
➔ nested_attributes
#devday2013@jlucasps
rails-2.3
class Book < ActiveRecord::Base
has_one :author
has_many :pages
accepts_nested_attributes_for :author, :pages
end
➔ find with having
developers = Developer.find(:all, :group => "salary", :having => "sum(salary)
> 10000", :select => "salary")
➔ Bundler and Gemfile
➔ New ActiveRecord query engine:
#devday2013@jlucasps
rails-3
users = User.where(:name => "david").limit(20)
users.order(:name).each { |user| puts user.name }
➔ Agnosticism with jQuery, rSpec, and Data
Mapper:
◆ DataMapper -> Active Record
◆ Query -> Prototype
◆ Spec -> test/unit
➔ AssetPipeline:
◆ Sprockets, SCSS, CoffeeScript
➔ JQuery by default
➔ Reversible migrations
#devday2013@jlucasps
rails-3.1
➔ critical security fixies:
◆ CVE-2012-5664
◆ CVE-2013-0155
◆ CVE-2013-0156
◆ CVE-2013-0333
➔ Vendor plugins -> gems
➔ Faster dev mode e routing
#devday2013@jlucasps
rails-3.2
#devday2013@jlucasps
rails-4
➔ Turbolinks
➔ Live streaming
➔ ActiveModel::Model
◆ validations, accessors, no persistence
➔ Deprecate routes by match
➔ Concerns routesconcern :commentable do
resources :comments
end
resources :articles, concerns: :commentable
resources :photos, concerns: :commentable
➔ Mass assignment protection from Models to
Controllers
#devday2013@jlucasps
rails-4
class MessagesController < ApplicationController def create @message = Message.new(message_params) @message.user = current_user @message.save end private def message_params params.require(:message).permit(:content) end end
Um roadmap do Framework Ruby on Rails
do Rails 1 ao Rails 4
João Lucas Pereira de Santana@jlucasps
Muito obrigado!