Slide 1

Slide 1 text

Um roadmap do Framework Ruby on Rails do Rails 1 ao Rails 4 João Lucas Pereira de Santana

Slide 2

Slide 2 text

#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

Slide 3

Slide 3 text

#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

Slide 4

Slide 4 text

#devday2013 @jlucasps Rails Full Stack ➔ Origem ◆ David Heinemeier Hansson

Slide 5

Slide 5 text

#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

Slide 6

Slide 6 text

➔ Framework MVC para desenvolvimento Web #devday2013 @jlucasps Rails Full Stack Testes Testes Testes Model View Controller HTTP/SSL Routes Helpers Middleware Responders Renders Session Logs Associations Validations Queries Callbacks Connections Migrations Assets Helpers Builders Templates Partials

Slide 7

Slide 7 text

#devday2013 @jlucasps Rails Full Stack Model View Controller Web Server App Server Rails request response

Slide 8

Slide 8 text

#devday2013 @jlucasps Rails Full Stack Model View Controller Web Server App Server Rails REQUEST: GET http://myapp.com/users/2/lists ACCEPTED: passado para o App Server Request passado para o Rails

Slide 9

Slide 9 text

#devday2013 @jlucasps Rails Full Stack Model View Controller Rails Router

Slide 10

Slide 10 text

#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"

Slide 11

Slide 11 text

#devday2013 @jlucasps Rails Full Stack Model View Controller Rails Router Controller ListsController Model View index new create update destroy ........ GET /users/2/lists CONTROLLER: "lists" ACTION: "index"

Slide 12

Slide 12 text

#devday2013 @jlucasps Rails Full Stack Model @user = User.find(params[:user_id]) @lists = List.find_all_by_user_id(params[:user_id]) ListsController index new create update destroy ........ User Model List Model Active Record Active Record Banco de dados tabela 'users' tabela 'lists'

Slide 13

Slide 13 text

#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 Rails Router action action action

Slide 14

Slide 14 text

#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 Headers Accept: text/html, application/xhtml+xml

Slide 15

Slide 15 text

#devday2013 @jlucasps Rails Full Stack HTTP Response

Slide 16

Slide 16 text

#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 Rails Router action action action VIEW cria a resposta para o RESPONSE BODY

Slide 17

Slide 17 text

#devday2013 @jlucasps Rails Full Stack Model View Controller Web Server App Server Rails 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 :-)

Slide 18

Slide 18 text

#devday2013 @jlucasps Rails Full Stack Response

Slide 19

Slide 19 text

➔ 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" }

Slide 20

Slide 20 text

➔ 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)

Slide 21

Slide 21 text

➔ 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

Slide 22

Slide 22 text

➔ 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

Slide 23

Slide 23 text

➔ 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 }

Slide 24

Slide 24 text

➔ 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

Slide 25

Slide 25 text

➔ active_record ◆ connections: ● db2, mysql, oracle, postgresql, sqlite, sqlite3, sqlserver ◆ mapping: #devday2013 @jlucasps rails-0.10.0 table "products" class Product < ActiveRecord::Base end

Slide 26

Slide 26 text

➔ 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

Slide 27

Slide 27 text

➔ 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

Slide 28

Slide 28 text

➔ 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

Slide 29

Slide 29 text

➔ active_record ◆ find and dynamic methods #devday2013 @jlucasps rails-0.10.0 # finds Firm.find(1, 2) Company.find_first "name = 'Next Angle'" Firm.find_by_sql("SELECT * FROM companies WHERE id = 1").first Topic.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 methods next_angle.clients.find(2) next_angle.clients.empty? next_angle.clients.size

Slide 30

Slide 30 text

➔ 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

Slide 31

Slide 31 text

➔ 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

Slide 32

Slide 32 text

➔ action_pack ◆ layouts: #devday2013 @jlucasps rails-0.10.0 class WeblogController < ActionController::Base layout "weblog_layout" def hello_world end end

Slide 33

Slide 33 text

➔ 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

Slide 34

Slide 34 text

➔ 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

Slide 35

Slide 35 text

➔ action_pack ◆ action view: #devday2013 @jlucasps rails-0.10.0 <% for post in @posts %> Title: <%= post.title %> <% end %> <%= text_field "post", "title", "size" => 30 %> <%= html_date_select(Date.today) %> <%= link_to "New post", :controller => "post", :action => "new" %> <%= truncate(post.title, 25) %>

Slide 36

Slide 36 text

➔ action_pack ◆ action view: #devday2013 @jlucasps rails-0.10.0 <%= form "post" %> <%= render_partial "advertisement/ad", ad %>

Slide 37

Slide 37 text

➔ 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 email

Slide 38

Slide 38 text

➔ 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

Slide 39

Slide 39 text

➔ Eager associations ➔ new Base.find API ➔ more Ajax! #devday2013 @jlucasps rails-0.12.0 # Turning N+1 queries into 1 for 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_on end 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)

Slide 40

Slide 40 text

➔ 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)" )

Slide 41

Slide 41 text

➔ 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 validations validates_numericality_of :income, :if => :employed? validates_presence_of :username, :if => Proc.new { |user| user.signup_step > 1 }

Slide 42

Slide 42 text

➔ 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

Slide 43

Slide 43 text

➔ 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"

Slide 44

Slide 44 text

➔ 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

Slide 45

Slide 45 text

➔ 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)

Slide 46

Slide 46 text

➔ 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")

Slide 47

Slide 47 text

➔ 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

Slide 48

Slide 48 text

➔ AssetPipeline: ◆ Sprockets, SCSS, CoffeeScript ➔ JQuery by default ➔ Reversible migrations #devday2013 @jlucasps rails-3.1

Slide 49

Slide 49 text

➔ 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

Slide 50

Slide 50 text

#devday2013 @jlucasps rails-4 ➔ Turbolinks ➔ Live streaming ➔ ActiveModel::Model ◆ validations, accessors, no persistence ➔ Deprecate routes by match ➔ Concerns routes concern :commentable do resources :comments end resources :articles, concerns: :commentable resources :photos, concerns: :commentable

Slide 51

Slide 51 text

➔ 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

Slide 52

Slide 52 text

Um roadmap do Framework Ruby on Rails do Rails 1 ao Rails 4 João Lucas Pereira de Santana @jlucasps Muito obrigado!