Um roadmap do Framework Ruby on Rails do Rails 1 ao Rails 4 João Lucas Pereira de Santana
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 @jlucasps #devday2013
Agenda ➔ Rails Full Stack - Request/Responder ➔ Primeira versão ◆ Active Support, Active Record, Action Pack, Action Mailer ➔ Rails 2 ➔ Rails 3 ➔ Rails 4 @jlucasps #devday2013
Rails Full Stack ➔ Origem ◆ David Heinemeier Hansson @jlucasps #devday2013
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 @jlucasps #devday2013
Rails Full Stack ➔ Framework MVC para desenvolvimento Web Session Helpers Logs Testes Middleware Controller Connections Validations Queries Callbacks Migrations @jlucasps Responders Routes Renders Assets Associations Testes HTTP/SSL Helpers Model View Builders Testes Templates Partials #devday2013
Rails Full Stack request Web Server App Server Rails Controller Model View response @jlucasps #devday2013
Rails Full Stack REQUEST: GET http://myapp.com/users/2/lists ACCEPTED: passado para o App Server Web Server App Server Request passado para o Rails Rails Controller Model @jlucasps View #devday2013
Rails Full Stack Rails Router Controller Model @jlucasps View #devday2013
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" @jlucasps #devday2013
Rails Full Stack Controller Rails Router index new create update Controller Model destroy ........ View GET /users/2/lists CONTROLLER: "lists" ACTION: "index" @jlucasps ListsController Model View #devday2013
Rails Full Stack Model @user = User.find(params[:user_id]) @lists = List.find_all_by_user_id(params[:user_id]) ListsController index new User Model Active Record tabela 'users' create Banco de dados update @jlucasps destroy ........ List Model Active Record tabela 'lists' #devday2013
Rails Full Stack REQUEST: GET http://myapp.com/users/2/lists ACCEPTED: passado para o App Server Web Server REQUEST passado para o Rails App Server Router CONTROLLER recupera informações dos MODELS para suprir a VIEW Rails PATH e METHOD mapeados para CONTROLLER e ACTION Controller action Model @jlucasps action action View #devday2013
Rails Full Stack View Request Headers Accept: text/html, application/xhtml+xml ListsController index View @vars @vars update app/views/lists/index.html.erb .html .html app/views/lists/update.html.erb edit .......... @jlucasps #devday2013
Rails Full Stack HTTP Response @jlucasps #devday2013
Rails Full Stack REQUEST: GET http://myapp.com/users/2/lists ACCEPTED: passado para o App Server Web Server REQUEST passado para o Rails App Server Router CONTROLLER recupera informações dos MODELS para suprir a VIEW VIEW cria a resposta para o RESPONSE BODY @jlucasps Rails PATH e METHOD mapeados para CONTROLLER e ACTION Controller action Model action action View #devday2013
Rails Full Stack RESPONSE recebida :-) RESPONSE é retornada para o browser Web Server RESPONSE volta através do middleware stack App Server Rails Router VIEW cria a resposta para o RESPONSE BODY @jlucasps Controller action Model action action View #devday2013
Rails Full Stack Response @jlucasps #devday2013
rails-0.10.0 ➔ Inflectors 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" } @jlucasps #devday2013
rails-0.10.0 ➔ Breakpoints [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) @jlucasps #devday2013
rails-0.10.0 ➔ active_support core_ext ◆ Time # 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 @jlucasps #devday2013
rails-0.10.0 ➔ active_support core_ext ◆ Numeric # byte calculations 1024.kilobytes => 1.kilobyte ** 4 => 1.megabyte 1.terabyte time calculations 1.minute => 60 1.hour + 15.minutes => 4500 2.days + 4.hours + 30.minutes => 189000 @jlucasps #devday2013
rails-0.10.0 ➔ active_support core_ext ◆ Hash # hash # stringify_keys, symbolize_keys e indifferent_access strings = { 'a' => 1, 'b' => 2 } symbols = { :a => 1, :b => 2 } mixed @jlucasps = { :a => 1, 'b' => 2 } #devday2013
rails-0.10.0 ➔ active_support core_ext ◆ Date # 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 @jlucasps #devday2013
rails-0.10.0 ➔ active_record ◆ connections: ● db2, mysql, oracle, postgresql, sqlite, sqlite3, sqlserver ◆ mapping: table "products" class Product < ActiveRecord::Base end @jlucasps #devday2013
rails-0.10.0 ➔ active_record ◆ associations: class Firm < ActiveRecord::Base has_many has_one :clients :account belongs_to :conglomorate has_and_belongs_to_many :investors end # natural assignments: apple.account = citibank assert_equal apple.id, citibank.firm_id @jlucasps #devday2013
rails-0.10.0 ➔ active_record ◆ validations: # 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 @jlucasps #devday2013
rails-0.10.0 ➔ active_record ◆ callbacks: # 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 @jlucasps #devday2013
rails-0.10.0 ➔ active_record ◆ find and dynamic methods # 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 @jlucasps #devday2013
rails-0.10.0 ➔ action_pack ◆ action_controller: BlogController < ActionController::Base def show @customer = find_customer end private def find_customer() Customer.find(@params["id"]) end end @jlucasps #devday2013
rails-0.10.0 ➔ action_pack ◆ filters: class WeblogController < ActionController::Base before_filter :authenticate, :cache, :audit after_filter { |c| c.response.body = GZip::compress(c.response.body) } end @jlucasps #devday2013
rails-0.10.0 ➔ action_pack ◆ layouts: class WeblogController < ActionController::Base layout "weblog_layout" def hello_world end end @jlucasps #devday2013
rails-0.10.0 ➔ action_pack ◆ scaffold: require 'account' # must be an Active Record class class AccountController < ActionController::Base scaffold :account end # templates: list, show, destroy, new, create, edit, update @jlucasps #devday2013
rails-0.10.0 ➔ action_pack ◆ advanced redirection # 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 @jlucasps #devday2013
rails-0.10.0 ➔ action_pack ◆ action view: <!-- 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) %> @jlucasps #devday2013
rails-0.10.0 ➔ action_pack ◆ action view: <!-- 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 %> @jlucasps #devday2013
rails-0.10.0 ➔ action_mailer def signed_up(recipient) @recipients = recipient @subject = "[Signed up] Welcome #{recipient}" @from = "system@loudthinking.com" @sent_on = Time.local(2004, 12, 12) @body["recipient"] = recipient end ApplicationMailer.deliver_signed_up("david@loudthinking.com") # sends the email @jlucasps #devday2013
rails-0.11.0 ➔ active_support ◆ string to date and time: 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 @jlucasps #devday2013
rails-0.12.0 ➔ Eager associations ➔ new Base.find API ➔ more Ajax! # 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) @jlucasps #devday2013
rails-0.13.0 ➔ script.aculo.us ➔ ajax # 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)" ) @jlucasps #devday2013
rails-0.13.0 ➔ Migrations for PostgreSQL and MySQL ➔ Rendering: One method to bind them all ➔ Named routes 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} @jlucasps #devday2013
rails-1.1.0 ➔ RJS: JavaScript written in Ruby ➔ Polymorphic associations 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 @jlucasps #devday2013
rails-1.1.0 ➔ calculations: ◆ sum, average, count, max ➔ Eager loading # 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 @jlucasps # => "Less software" #devday2013
rails-1.2 ➔ respond_to e format 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 @jlucasps #devday2013
rails-2 ➔ action_pack: ◆ resources e collection resources ◆ multiview (show.html.erb, show.js.erb) ◆ CRSF token ◆ record identification: # 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) @jlucasps #devday2013
rails-2.3 ➔ nested_attributes 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") @jlucasps #devday2013
rails-3 ➔ Bundler and Gemfile ➔ New ActiveRecord query engine: 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 @jlucasps #devday2013
rails-3.1 ➔ AssetPipeline: ◆ Sprockets, SCSS, CoffeeScript ➔ JQuery by default ➔ Reversible migrations @jlucasps #devday2013
rails-3.2 ➔ critical security fixies: ◆ CVE-2012-5664 ◆ CVE-2013-0155 ◆ CVE-2013-0156 ◆ CVE-2013-0333 ➔ Vendor plugins -> gems ➔ Faster dev mode e routing @jlucasps #devday2013
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 @jlucasps #devday2013
rails-4 ➔ Mass assignment protection from Models to Controllers 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 @jlucasps #devday2013
Muito obrigado! Um roadmap do Framework Ruby on Rails do Rails 1 ao Rails 4 João Lucas Pereira de Santana @jlucasps

Um roadmap do Framework Ruby on Rails, do Rails 1 ao Rails 4 - DevDay 2013

  • 1.
    Um roadmap do FrameworkRuby on Rails do Rails 1 ao Rails 4 João Lucas Pereira de Santana
  • 2.
    Apresentação João Lucas Pereirade Santana twitter | github | fb | gtalk: @jlucasps Ciência da Computação pela UFLA Desenvolvedor Ruby, Java, JavaScript Instrutor Ruby on Rails @jlucasps #devday2013
  • 3.
    Agenda ➔ Rails FullStack - Request/Responder ➔ Primeira versão ◆ Active Support, Active Record, Action Pack, Action Mailer ➔ Rails 2 ➔ Rails 3 ➔ Rails 4 @jlucasps #devday2013
  • 4.
    Rails Full Stack ➔Origem ◆ David Heinemeier Hansson @jlucasps #devday2013
  • 5.
    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 @jlucasps #devday2013
  • 6.
    Rails Full Stack ➔Framework MVC para desenvolvimento Web Session Helpers Logs Testes Middleware Controller Connections Validations Queries Callbacks Migrations @jlucasps Responders Routes Renders Assets Associations Testes HTTP/SSL Helpers Model View Builders Testes Templates Partials #devday2013
  • 7.
    Rails Full Stack request WebServer App Server Rails Controller Model View response @jlucasps #devday2013
  • 8.
    Rails Full Stack REQUEST: GEThttp://myapp.com/users/2/lists ACCEPTED: passado para o App Server Web Server App Server Request passado para o Rails Rails Controller Model @jlucasps View #devday2013
  • 9.
  • 10.
    Rails Full Stack Router user_listsGET /users/:user_id/lists(.:format) lists#index Controller e Action selecionadas: GET /users/2/lists CONTROLLER: "lists" ACTION: "index" NOME DA ROTA: "user_lists" @jlucasps #devday2013
  • 11.
    Rails Full Stack Controller Rails Router index new create update Controller Model destroy ........ View GET/users/2/lists CONTROLLER: "lists" ACTION: "index" @jlucasps ListsController Model View #devday2013
  • 12.
    Rails Full Stack Model @user= User.find(params[:user_id]) @lists = List.find_all_by_user_id(params[:user_id]) ListsController index new User Model Active Record tabela 'users' create Banco de dados update @jlucasps destroy ........ List Model Active Record tabela 'lists' #devday2013
  • 13.
    Rails Full Stack REQUEST: GEThttp://myapp.com/users/2/lists ACCEPTED: passado para o App Server Web Server REQUEST passado para o Rails App Server Router CONTROLLER recupera informações dos MODELS para suprir a VIEW Rails PATH e METHOD mapeados para CONTROLLER e ACTION Controller action Model @jlucasps action action View #devday2013
  • 14.
    Rails Full Stack View RequestHeaders Accept: text/html, application/xhtml+xml ListsController index View @vars @vars update app/views/lists/index.html.erb .html .html app/views/lists/update.html.erb edit .......... @jlucasps #devday2013
  • 15.
    Rails Full Stack HTTPResponse @jlucasps #devday2013
  • 16.
    Rails Full Stack REQUEST: GEThttp://myapp.com/users/2/lists ACCEPTED: passado para o App Server Web Server REQUEST passado para o Rails App Server Router CONTROLLER recupera informações dos MODELS para suprir a VIEW VIEW cria a resposta para o RESPONSE BODY @jlucasps Rails PATH e METHOD mapeados para CONTROLLER e ACTION Controller action Model action action View #devday2013
  • 17.
    Rails Full Stack RESPONSErecebida :-) RESPONSE é retornada para o browser Web Server RESPONSE volta através do middleware stack App Server Rails Router VIEW cria a resposta para o RESPONSE BODY @jlucasps Controller action Model action action View #devday2013
  • 18.
  • 19.
    rails-0.10.0 ➔ Inflectors 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" } @jlucasps #devday2013
  • 20.
    rails-0.10.0 ➔ Breakpoints [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) @jlucasps #devday2013
  • 21.
    rails-0.10.0 ➔ active_support core_ext ◆Time # 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 @jlucasps #devday2013
  • 22.
    rails-0.10.0 ➔ active_support core_ext ◆Numeric # byte calculations 1024.kilobytes => 1.kilobyte ** 4 => 1.megabyte 1.terabyte time calculations 1.minute => 60 1.hour + 15.minutes => 4500 2.days + 4.hours + 30.minutes => 189000 @jlucasps #devday2013
  • 23.
    rails-0.10.0 ➔ active_support core_ext ◆Hash # hash # stringify_keys, symbolize_keys e indifferent_access strings = { 'a' => 1, 'b' => 2 } symbols = { :a => 1, :b => 2 } mixed @jlucasps = { :a => 1, 'b' => 2 } #devday2013
  • 24.
    rails-0.10.0 ➔ active_support core_ext ◆Date # 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 @jlucasps #devday2013
  • 25.
    rails-0.10.0 ➔ active_record ◆ connections: ●db2, mysql, oracle, postgresql, sqlite, sqlite3, sqlserver ◆ mapping: table "products" class Product < ActiveRecord::Base end @jlucasps #devday2013
  • 26.
    rails-0.10.0 ➔ active_record ◆ associations: classFirm < ActiveRecord::Base has_many has_one :clients :account belongs_to :conglomorate has_and_belongs_to_many :investors end # natural assignments: apple.account = citibank assert_equal apple.id, citibank.firm_id @jlucasps #devday2013
  • 27.
    rails-0.10.0 ➔ active_record ◆ validations: #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 @jlucasps #devday2013
  • 28.
    rails-0.10.0 ➔ active_record ◆ callbacks: #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 @jlucasps #devday2013
  • 29.
    rails-0.10.0 ➔ active_record ◆ findand dynamic methods # 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 @jlucasps #devday2013
  • 30.
    rails-0.10.0 ➔ action_pack ◆ action_controller: BlogController< ActionController::Base def show @customer = find_customer end private def find_customer() Customer.find(@params["id"]) end end @jlucasps #devday2013
  • 31.
    rails-0.10.0 ➔ action_pack ◆ filters: classWeblogController < ActionController::Base before_filter :authenticate, :cache, :audit after_filter { |c| c.response.body = GZip::compress(c.response.body) } end @jlucasps #devday2013
  • 32.
    rails-0.10.0 ➔ action_pack ◆ layouts: classWeblogController < ActionController::Base layout "weblog_layout" def hello_world end end @jlucasps #devday2013
  • 33.
    rails-0.10.0 ➔ action_pack ◆ scaffold: require'account' # must be an Active Record class class AccountController < ActionController::Base scaffold :account end # templates: list, show, destroy, new, create, edit, update @jlucasps #devday2013
  • 34.
    rails-0.10.0 ➔ action_pack ◆ advancedredirection # 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 @jlucasps #devday2013
  • 35.
    rails-0.10.0 ➔ action_pack ◆ actionview: <!-- 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) %> @jlucasps #devday2013
  • 36.
    rails-0.10.0 ➔ action_pack ◆ actionview: <!-- 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 %> @jlucasps #devday2013
  • 37.
    rails-0.10.0 ➔ action_mailer def signed_up(recipient) @recipients =recipient @subject = "[Signed up] Welcome #{recipient}" @from = "system@loudthinking.com" @sent_on = Time.local(2004, 12, 12) @body["recipient"] = recipient end ApplicationMailer.deliver_signed_up("david@loudthinking.com") # sends the email @jlucasps #devday2013
  • 38.
    rails-0.11.0 ➔ active_support ◆ stringto date and time: 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 @jlucasps #devday2013
  • 39.
    rails-0.12.0 ➔ Eager associations ➔new Base.find API ➔ more Ajax! # 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) @jlucasps #devday2013
  • 40.
    rails-0.13.0 ➔ script.aculo.us ➔ ajax #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)" ) @jlucasps #devday2013
  • 41.
    rails-0.13.0 ➔ Migrations forPostgreSQL and MySQL ➔ Rendering: One method to bind them all ➔ Named routes 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} @jlucasps #devday2013
  • 42.
    rails-1.1.0 ➔ RJS: JavaScriptwritten in Ruby ➔ Polymorphic associations 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 @jlucasps #devday2013
  • 43.
    rails-1.1.0 ➔ calculations: ◆ sum,average, count, max ➔ Eager loading # 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 @jlucasps # => "Less software" #devday2013
  • 44.
    rails-1.2 ➔ respond_to eformat 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 @jlucasps #devday2013
  • 45.
    rails-2 ➔ action_pack: ◆ resourcese collection resources ◆ multiview (show.html.erb, show.js.erb) ◆ CRSF token ◆ record identification: # 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) @jlucasps #devday2013
  • 46.
    rails-2.3 ➔ nested_attributes 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") @jlucasps #devday2013
  • 47.
    rails-3 ➔ Bundler andGemfile ➔ New ActiveRecord query engine: 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 @jlucasps #devday2013
  • 48.
    rails-3.1 ➔ AssetPipeline: ◆ Sprockets,SCSS, CoffeeScript ➔ JQuery by default ➔ Reversible migrations @jlucasps #devday2013
  • 49.
    rails-3.2 ➔ critical securityfixies: ◆ CVE-2012-5664 ◆ CVE-2013-0155 ◆ CVE-2013-0156 ◆ CVE-2013-0333 ➔ Vendor plugins -> gems ➔ Faster dev mode e routing @jlucasps #devday2013
  • 50.
    rails-4 ➔ Turbolinks ➔ Livestreaming ➔ 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 @jlucasps #devday2013
  • 51.
    rails-4 ➔ Mass assignmentprotection from Models to Controllers 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 @jlucasps #devday2013
  • 52.
    Muito obrigado! Um roadmapdo Framework Ruby on Rails do Rails 1 ao Rails 4 João Lucas Pereira de Santana @jlucasps