Rails 3: Dashing to the Finish
Upcoming SlideShare
Loading in...5
×

Like this? Share it with your network

Share
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Be the first to comment
No Downloads

Views

Total Views
15,105
On Slideshare
14,287
From Embeds
818
Number of Embeds
16

Actions

Shares
Downloads
456
Comments
0
Likes
43

Embeds 818

http://www.slideshare.net 686
http://www.funonrails.com 93
http://localhost 9
http://feeds.feedburner.com 8
http://www.lmodules.com 5
http://teamco-anthill.blogspot.com 4
http://josephstalin.com:3000 2
http://translate.googleusercontent.com 2
http://funonrails.com 2
http://www.youngdigitallab.com 1
http://laureleiv.blogspot.com 1
http://s.deeeki.com 1
http://localhost:3000 1
http://seekr-artemis.heroku.com 1
http://www.linkedin.com 1
http://twittertim.es 1

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
    No notes for slide

Transcript

  • 1. { Rails 3
  • 2. Overview
  • 3. Dashing to the Finish
  • 4. A Lot Like Rails 2.3
  • 5. Quick Refresher
  • 6. What Hasn’t Changed?
  • 7. MVC
  • 8. REST
  • 9. Resources
  • 10. Controllers
  • 11. Migrations
  • 12. AR Ideas
  • 13. Big User-Facing Changes
  • 14. File Structure
  • 15. con g.ru # This file is used by Rack-based # servers to start the application. require ::File.expand_path( '../config/environment', __FILE__ ) run Tutorial::Application
  • 16. con g/boot.rb require 'rubygems' # Set up gems listed in the Gemfile. gemfile = File.expand_path( '../../Gemfile', __FILE__ ) if File.exist?(gemfile) ENV['BUNDLE_GEMFILE'] = gemfile require 'bundler' Bundler.setup end
  • 17. Gem le source 'http://rubygems.org' gem 'rails', '3.0.0.beta3' gem 'sqlite3-ruby'
  • 18. con g/environment.rb # Load the rails application require File.expand_path( '../application', __FILE__ ) # Initialize the rails application Tutorial::Application.initialize!
  • 19. con g/application.rb (1) require File.expand_path( '../boot', __FILE__ ) require 'rails/all' if defined?(Bundler) Bundler.require(:default, Rails.env) end
  • 20. con g/application.rb (2) module Tutorial class Application < Rails::Application config.encoding = "utf-8" config.filter_parameters += [:password] end end
  • 21. environments/production.rb Tutorial::Application.configure do config.cache_classes = true config.consider_all_requests_local = false config.action_controller.perform_caching = true config.action_dispatch.x_sendfile_header = "X-Sendfile" config.serve_static_assets = false end
  • 22. initializers/session_store.rb Rails.application. config.session_store( :cookie_store, :key => '_tutorial_session' )
  • 23. script/rails (1) #!/usr/bin/env ruby # This command will automatically # be run when you run "rails" with # Rails 3 gems installed from the # root of your application. ENV_PATH = File.expand_path( '../../config/environment', __FILE__ )
  • 24. script/rails (2) BOOT_PATH = File.expand_path( '../../config/boot', __FILE__ ) APP_PATH = File.expand_path( '../../config/application', __FILE__ ) require BOOT_PATH require 'rails/commands'
  • 25. Recent
  • 26. Even Easier to Remove Bundler
  • 27. Removing Bundler $ rm Gemfile
  • 28. app/mailers $ script/rails g mailer welcome create app/mailers/welcome.rb invoke erb create app/views/welcome invoke test_unit create test/functional/welcome_test.rb
  • 29. app/layouts/application.html.erb <!DOCTYPE html> <html> <head> <title>Tutorial</title> <%= stylesheet_link_tag :all %> <%= javascript_include_tag :defaults %> <%= csrf_meta_tag %> </head> <body> <%= yield %> </body> </html>
  • 30. public/ javascripts/ rails.js
  • 31. github.com/ rails/jquery-ujs
  • 32. db/seeds.rb
  • 33. rake db:setup
  • 34. db:create db:schema:load db:seed
  • 35. lib/tasks/setup.rake task :bundle do system "bundle install" end task :setup => ["bundle", "db:setup"]
  • 36. Rails Command ★ generate | g ★ destroy ★ console | c ★ benchmarker ★ server | s ★ profiler ★ dbconsole | db ★ plugin ★ application ★ runner
  • 37. Block Helpers
  • 38. Block Helpers (Before) <% form_for @post do |f| %> <%= f.input_field :name %> <% end %>
  • 39. Block Helpers (Before) <% box do %> <p>Hello World!</p> <% end %>
  • 40. Block Helpers (Before) def box(&block) content = "<div class='box'>" << capture(&block) << "</div>" if block_called_from_erb? concat(content) else content end end
  • 41. Block Helpers (After) <%= box do %> <p>Hello World!</p> <% end %>
  • 42. Block Helpers (After) def box(&block) "<div class='box'>" "#{capture(&block)}" "</div>" end
  • 43. Block Helpers (After) def box(&block) "<div class='box'>" "#{capture(&block)}" "</div>".html_safe end
  • 44. Recent
  • 45. Tons of Fixes to XSS Safe
  • 46. Lots of XSS- Related Changes to Your App...
  • 47. You’re Doing it Wrong
  • 48. Router
  • 49. Note: Signi cant Changes Ahead
  • 50. Also Note: Old Mapper Still Available
  • 51. Matching map.connect "posts", :controller => :posts, :action => :index
  • 52. Matching map.connect "posts", :controller => :posts, :action => :index match "posts" => "posts#index"
  • 53. Optional Segments match "/posts(/page)" => "posts#index"
  • 54. Optional Dynamic Segments match "/posts(/:id)" => "posts#index"
  • 55. Default Parameters match "/posts(/:id)" => "posts#index", :defaults => {:id => 1}
  • 56. Default Parameters match "/posts(/:id)" => "posts#index", :id => 1
  • 57. Named Routes match "/posts(/:id)" => "posts#index", :id => 1, :as => "posts"
  • 58. The Root root :to => "posts#index"
  • 59. Scopes
  • 60. Path Scope match "/admin/posts" => "posts#index" match "/admin/users" => "users#index"
  • 61. Path Scope match "/admin/posts" => "posts#index" match "/admin/users" => "users#index" scope :path => "admin" do match "/posts" => "posts#index" match "/users" => "users#index" end
  • 62. Path Scope match "/admin/posts" => "posts#index" match "/admin/users" => "users#index" scope "admin" do match "/posts" => "posts#index" match "/users" => "users#index" end
  • 63. Module Scope match "/posts" => "admin/posts#index" match "/users" => "admin/users#index"
  • 64. Module Scope match "/posts" => "admin/posts#index" match "/users" => "admin/users#index" scope :module => "admin" do match "/posts" => "posts#index" match "/users" => "users#index" end
  • 65. Both match "admin/posts" => "admin/posts#index" match "admin/users" => "admin/users#index"
  • 66. Both match "admin/posts" => "admin/posts#index" match "admin/users" => "admin/users#index" namespace "admin" do match "/posts" => "posts#index" match "/users" => "users#index" end
  • 67. HTTP Methods
  • 68. Get Request match "/posts" => "posts#index", :via => "get"
  • 69. Get Request match "/posts" => "posts#index", :via => "get" get "/posts" => "posts#index"
  • 70. Scoping scope "/posts" do controller :posts do get "/" => :index end end
  • 71. Scoping scope "/posts" do controller :posts do get "/" => :index end end get "/posts" => "posts#index"
  • 72. Default Resource Route controller :posts do scope "/posts" do get "/" => :index post "/" => :create get "/:id" => :show put "/:id" => :update delete "/:id" => :delete get "/new" => :new get "/:id/edit" => :edit end end
  • 73. Default Resource Route controller :posts do scope "/posts" do get "/" => :index, :as => :posts post "/" => :create get "/:id" => :show, :as => :post put "/:id" => :update delete "/:id" => :delete get "/new" => :new, :as => :new_post get "/:id/edit" => :edit, :as => :edit_post end end
  • 74. Constraints
  • 75. Regex Constraint get "/:id" => "posts#index", :constraints => {:id => /d+/}
  • 76. Regex Constraint get "/:id" => "posts#index", :id => /d+/
  • 77. Request-Based Constraint get "/mobile" => "posts#index", :constraints => {:user_agent => /iPhone/}
  • 78. Request-Based Constraint get "/mobile" => "posts#index", :constraints => {:user_agent => /iPhone/}, :defaults => {:mobile => true}
  • 79. Request-Based Constraint get "/mobile" => "posts#index", :user_agent => /iPhone/, :mobile => true
  • 80. Object Constraints class DubDubConstraint def self.matches?(request) request.host =~ /^(www.)/ end end get "/" => "posts#index", :constraints => DubDubConstraint
  • 81. Rack
  • 82. Equivalent get "/posts" => "posts#index"
  • 83. Equivalent get "/posts" => "posts#index" get "/posts" => PostsController.action(:index)
  • 84. Rack >> a = PostsController.action(:index)
  • 85. Rack >> a = PostsController.action(:index) => #<Proc:0x0000000103d050d0@/Users/ wycats/Code/rails/actionpack/lib/ action_controller/metal.rb:123>
  • 86. Rack >> a = PostsController.action(:index) => #<Proc:0x0000000103d050d0@/Users/ wycats/Code/rails/actionpack/lib/ action_controller/metal.rb:123> >> e = Rack::MockRequest.env_for("/")
  • 87. Rack >> a = PostsController.action(:index) => #<Proc:0x0000000103d050d0@/Users/ wycats/Code/rails/actionpack/lib/ action_controller/metal.rb:123> >> e = Rack::MockRequest.env_for("/") => {"SERVER_NAME"=>"example.org", "CONTENT_LENGTH"=>"0", ...}
  • 88. Rack >> a = PostsController.action(:index) => #<Proc:0x0000000103d050d0@/Users/ wycats/Code/rails/actionpack/lib/ action_controller/metal.rb:123> >> e = Rack::MockRequest.env_for("/") => {"SERVER_NAME"=>"example.org", "CONTENT_LENGTH"=>"0", ...} >> e.call(a)
  • 89. Rack >> a = PostsController.action(:index) => #<Proc:0x0000000103d050d0@/Users/ wycats/Code/rails/actionpack/lib/ action_controller/metal.rb:123> >> e = Rack::MockRequest.env_for("/") => {"SERVER_NAME"=>"example.org", "CONTENT_LENGTH"=>"0", ...} >> e.call(a) => [200, {"ETag"=> '"eca5953f36da05ff351d712d904e"', ...}, ["Hello World"]]
  • 90. Match to Rack class MyApp def call(env) [200, {"Content-Type" => "text/html"}, ["Hello World"]] end end get "/" => MyApp.new
  • 91. Redirection get "/" => redirect("/foo")
  • 92. Redirection get "/" => redirect("/foo") get "/:id" => redirect("/posts/%{id}") get "/:id" => redirect("/posts/%s")
  • 93. Redirection get "/" => redirect("/foo") get "/:id" => redirect("/posts/%{id}") get "/:id" => redirect("/posts/%s") get "/:id" => redirect { |params, req| ... }
  • 94. Rack App def redirect(*args, &block) options = args.last.is_a?(Hash) ? args.pop : {} path = args.shift || block path_proc = path.is_a?(Proc) ? path : proc { |params| path % params } status = options[:status] || 301 body = 'Moved Permanently' lambda do |env| req = Request.new(env) params = [req.symbolized_path_parameters] params << req if path_proc.arity > 1 uri = URI.parse(path_proc.call(*params)) uri.scheme ||= req.scheme uri.host ||= req.host uri.port ||= req.port unless req.port == 80 headers = { 'Location' => uri.to_s, 'Content-Type' => 'text/html', 'Content-Length' => body.length.to_s } [ status, headers, [body] ] end end
  • 95. Rack App def redirect(*args, &block) options = args.last.is_a?(Hash) ? args.pop : {} path = args.shift || block path_proc = path.is_a?(Proc) ? path : proc { |params| path % params } status = options[:status] || 301 body = 'Moved Permanently' lambda do |env| req = Request.new(env) redirect(*args, &block) params = [req.symbolized_path_parameters] params << req if path_proc.arity > 1 uri = URI.parse(path_proc.call(*params)) uri.scheme ||= req.scheme uri.host ||= req.host uri.port ||= req.port unless req.port == 80 headers = { 'Location' => uri.to_s, 'Content-Type' => 'text/html', 'Content-Length' => body.length.to_s } [ status, headers, [body] ] end end
  • 96. Rack App lambda do |env| req = Request.new(env) params = [req.symbolized_path_parameters] params << req if path_proc.arity > 1 uri = URI.parse(path_proc.call(*params)) uri.scheme ||= req.scheme uri.host ||= req.host uri.port ||= req.port unless req.port == 80 headers = { 'Location' => uri.to_s, 'Content-Type' => 'text/html', 'Content-Length' => body.length.to_s } [ status, headers, [body] ] end
  • 97. Rack App lambda do |env| req = Request.new(env) params = [req.symbolized_path_parameters] params << req if path_proc.arity > 1 uri = URI.parse(path_proc.call(*params)) [ status, headers, [body] ] uri.scheme ||= req.scheme uri.host ||= req.host uri.port ||= req.port unless req.port == 80 headers = { 'Location' => uri.to_s, 'Content-Type' => 'text/html', 'Content-Length' => body.length.to_s } [ status, headers, [body] ] end
  • 98. Resources
  • 99. Resources resources :magazines do resources :ads end
  • 100. Member Resources resources :photos do member do get :preview get :print end end
  • 101. One-Offs resources :photos do get :preview, :on => :member end
  • 102. Collections resources :photos do collection do get :search end end
  • 103. Combination scope :module => "admin" do constraints IpBlacklist do resources :posts, :comments end end
  • 104. Recent
  • 105. #mount
  • 106. Rack Endpoint class MountedEndpoint def call(env) head = {"Content-Type" => "text/html"} body = "script: #{env["SCRIPT_NAME"]}" body += "path: #{env["PATH_INFO"]}" [200, head, [body]] end end
  • 107. Mounting class MountedEndpoint def call(env) head = {"Content-Type" => "text/html"} body = "script: #{env["SCRIPT_NAME"]}" body += "path: #{env["PATH_INFO"]}" [200, head, [body]] end end mount "/end", :at => MountedEndpoint.new
  • 108. Mounting class MountedEndpoint def call(env) head = {"Content-Type" => "text/html"} body = "script: #{env["SCRIPT_NAME"]}" body += "path: #{env["PATH_INFO"]}" [200, head, [body]] end end mount "/end", :at => MountedEndpoint.new # "/end/point" => # script: /end # path: /point
  • 109. Sinatra!
  • 110. ActiveRecord
  • 111. New Chainable, Lazy API
  • 112. Chainable Methods ★ select ★ order ★ from ★ limit ★ where ★ offset ★ joins ★ includes ★ having ★ lock ★ group ★ readonly
  • 113. Controller def index @posts = Post. where(:published => true). order("publish_date desc") end
  • 114. Model def index @posts = Post.published end class Post < ActiveRecord::Base scope :published, where(:published => true). order("publish_date desc") end
  • 115. Model class Post < ActiveRecord::Base scope :desc, order("publish_date desc") scope :published, where(:published => true).desc end
  • 116. Controller def index @posts = Post. where("created_at < ?", Time.now). order("publish_date desc") end
  • 117. Controller def index @posts = Post.past end class Post < ActiveRecord::Base scope :desc, order("publish_date desc") def self.past where("created_at < ?", Time.now).desc end end
  • 118. Model class Post < ActiveRecord::Base scope :desc, order("publish_date desc") def self.past where("created_at < ?", Time.now).desc end def self.recent(number) past.limit(5) end end
  • 119. Pagination class PostsController < ApplicationController def index @posts = Posts.page(5, :per_page => 10) end end class Post < ActiveRecord::Base def self.page(number, options) per_page = options[:per_page] offset(per_page * (number - 1)). limit(per_page) end end
  • 120. named_scope with_scope nd(:all)
  • 121. scope
  • 122. ActionMailer
  • 123. Massive API Overhaul
  • 124. Sending Emails def welcome(user) @user = user mail(:to => user.email, :subject => "Welcome man!") end
  • 125. welcome.text.erb welcome.html.erb
  • 126. Layouts layout "rails_dispatch" def welcome(user) @user = user mail(:to => user.email, :subject => "Welcome man!") end
  • 127. rails_dispatch.text.erb rails_dispatch.html.erb
  • 128. Be More Speci c def welcome(user) @user = user mail(:to => user.email, :subject => "Welcome man!") do |format| format.html format.text { render "generic" } end end
  • 129. Defaults default :from => "wycats@gmail.com" def welcome(user) @user = user mail(:to => user.email, :subject => "Welcome man!") do |format| format.html format.text { render "generic" } end end
  • 130. Attachments def welcome(user) @user = user file = Rails.public_path.join("hello.pdf") contents = File.read(file) attachments["welcome.pdf"] = contents mail(:to => user.email, :subject => "Welcome man!") end
  • 131. Interceptors class MyInterceptor def self.delivering_email(mail) original = mail.to mail.to = "wycats@gmail.com" mail.subject = "#{original}: #{mail.subject}" end end
  • 132. Interceptors class MyInterceptor def self.delivering_email(mail) original = mail.to mail.to = "wycats@gmail.com" mail.subject = "#{original}: #{mail.subject}" end end config.action_mailer. register_interceptor(MyInterceptor)
  • 133. Interceptors Delivery Observers
  • 134. delivering_mail deliver delivered_mail
  • 135. Bundler
  • 136. bundle install
  • 137. bundle lock
  • 138. bundle lock
  • 139. .gitignore .dot les
  • 140. Engine Yard Heroku chef
  • 141. Engine Yard Heroku chef capistrano?
  • 142. gembundler.com
  • 143. gembundler.com /rails3.html
  • 144. railsdispatch.com /posts/bundler
  • 145. yehudakatz.com/ 2010/04/12/some-of- the-problems- bundler-solves/
  • 146. yehudakatz.com/ 2010/04/17/ruby- require-order- problems/
  • 147. Choices
  • 148. rspec-rails
  • 149. generators rake tasks controller_example view_example request_example mailer_example
  • 150. Mailer Generator $ script/rails g mailer welcome create app/mailers/welcome.rb invoke erb create app/views/welcome invoke rspec create spec/mailers/welcome_spec.rb
  • 151. dm-rails
  • 152. generators rake tasks append_info_to_payload i18n_scope IdentityMap middleware
  • 153. generate a resource $ rails g resource comment invoke data_mapper create app/models/comment.rb invoke test_unit create test/unit/comment_test.rb create test/fixtures/comments.yml invoke controller create app/controllers/comments_controller.rb invoke erb create app/views/commentses invoke test_unit create test/functional/comments_controller_test.rb invoke helper create app/helpers/commentses_helper.rb invoke test_unit create test/unit/helpers/comments_helper_test.rb route resources :commentses
  • 154. generate a resource $ rails g resource comment invoke data_mapper create app/models/comment.rb invoke rspec create spec/models/comment_spec.rb invoke controller create app/controllers/comments_controller.rb invoke erb create app/views/comments invoke rspec create spec/controllers/comments_controller_spec.rb create spec/views/comments invoke helper create app/helpers/comments_helper.rb invoke rspec route resources :comments
  • 155. rails g $ rails g Rails: controller generator helper integration_test mailer metal migration model observer performance_test plugin resource scaffold scaffold_controller session_migration stylesheets
  • 156. What Else?
  • 157. Ruby 1.9 Encoding
  • 158. Mission
  • 159. You Can Assume UTF-8 Inside of Rails
  • 160. (unless you want to handle encodings yourself)
  • 161. Testing
  • 162. RSpec Driven Effort
  • 163. Rails Testing Support Becomes Modular
  • 164. ActionController Middleware class PostsController use MyMiddleware, :only => :index end
  • 165. Metal becomes AC::Metal
  • 166. i18n Check Out Sven’s Talk Last slot in conference
  • 167. Trimming ActiveSupport Dependencies
  • 168. Thanks!
  • 169. Questions?