Rails 3 overview

6,907
-1

Published on

Published in: Technology
0 Comments
26 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total Views
6,907
On Slideshare
0
From Embeds
0
Number of Embeds
6
Actions
Shares
0
Downloads
273
Comments
0
Likes
26
Embeds 0
No embeds

No notes for slide

Rails 3 overview

  1. 1. { Rails 3
  2. 2. Overview
  3. 3. A Lot Like Rails 2.3
  4. 4. Quick Refresher
  5. 5. What Hasn’t Changed?
  6. 6. MVC
  7. 7. REST
  8. 8. Resources
  9. 9. Controllers
  10. 10. Migrations
  11. 11. AR Ideas
  12. 12. Big User-Facing Changes
  13. 13. File Structure
  14. 14. 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
  15. 15. 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
  16. 16. Gem le source 'http://rubygems.org' gem 'rails', '3.0.0.beta3' gem 'sqlite3-ruby', :require => 'sqlite3'
  17. 17. con g/environment.rb # Load the rails application require File.expand_path( '../application', __FILE__ ) # Initialize the rails application Tutorial::Application.initialize!
  18. 18. con g/application.rb (1) require File.expand_path( '../boot', __FILE__ ) require 'rails/all' if defined?(Bundler) Bundler.require(:default, Rails.env) end
  19. 19. con g/application.rb (2) module Tutorial class Application < Rails::Application config.encoding = "utf-8" config.filter_parameters += [:password] end end
  20. 20. 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
  21. 21. initializers/session_store.rb Rails.application. config.session_store( :cookie_store, :key => '_tutorial_session' )
  22. 22. 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__ )
  23. 23. 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'
  24. 24. 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
  25. 25. 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>
  26. 26. public/ javascripts/ rails.js
  27. 27. github.com/ rails/jquery-ujs
  28. 28. db/seeds.rb
  29. 29. rake db:setup
  30. 30. db:create db:schema:load db:seed
  31. 31. lib/tasks/setup.rake task :bundle do system "bundle install" end task :setup => ["bundle", "db:setup"]
  32. 32. Rails Command ★ generate | g ★ destroy ★ console | c ★ benchmarker ★ server | s ★ profiler ★ dbconsole | db ★ plugin ★ application ★ runner
  33. 33. Block Helpers
  34. 34. Block Helpers (Before) <% form_for @post do |f| %> <% end %>
  35. 35. Block Helpers (Before) <% box do %> <p>Hello World!</p> <% end %>
  36. 36. Block Helpers (Before) def box(&block) content = "<div class='box'>" << capture(&block) << "</div>" if block_called_from_erb? concat(content) else content end end
  37. 37. Block Helpers (After) <%= box do %> <p>Hello World!</p> <% end %>
  38. 38. Block Helpers (After) def box(&block) "<div class='box'>" "#{capture(&block)}" "</div>" end
  39. 39. Block Helpers (After) def box(&block) "<div class='box'>" "#{capture(&block)}" "</div>".html_safe end
  40. 40. Router
  41. 41. Note: Signi cant Changes Ahead
  42. 42. Also Note: Old Mapper Still Available
  43. 43. Matching map.connect "posts", :controller => :posts, :action => :index
  44. 44. Matching map.connect "posts", :controller => :posts, :action => :index match "posts" => "posts#index"
  45. 45. Matching map.connect "posts", :controller => :posts, :action => :index match "/posts" => "posts#index"
  46. 46. Optional Segments match "/posts(/page)" => "posts#index"
  47. 47. Optional Dynamic Segments match "/posts(/:id)" => "posts#index"
  48. 48. Default Parameters match "/posts(/:id)" => "posts#index", :defaults => {:id => 1}
  49. 49. Default Parameters match "/posts(/:id)" => "posts#index", :id => 1
  50. 50. Named Routes match "/posts(/:id)" => "posts#index", :id => 1, :as => "posts"
  51. 51. The Root root :to => "posts#index"
  52. 52. Scopes
  53. 53. Path Scope match "/admin/posts" => "posts#index" match "/admin/users" => "users#index"
  54. 54. Path Scope scope :path => "admin" do match "/posts" => "posts#index" match "/users" => "users#index" end
  55. 55. Path Scope scope "admin" do match "/posts" => "posts#index" match "/users" => "users#index" end
  56. 56. Module Scope match "/posts" => "admin/posts#index" match "/users" => "admin/users#index"
  57. 57. Module Scope scope :module => "admin" do match "/posts" => "posts#index" match "/users" => "users#index" end
  58. 58. Both match "admin/posts" => "admin/posts#index" match "admin/users" => "admin/users#index"
  59. 59. Both namespace "admin" do match "/posts" => "posts#index" match "/users" => "users#index" end
  60. 60. HTTP Methods
  61. 61. Get Request match "/posts" => "posts#index", :via => "get"
  62. 62. Get Request get "/posts" => "posts#index"
  63. 63. Scoping scope "/posts" do controller :posts do get "/" => :index end end
  64. 64. Scoping get "/posts" => "posts#index"
  65. 65. 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
  66. 66. 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
  67. 67. Constraints
  68. 68. Regex Constraint get "/:id" => "posts#index", :constraints => {:id => /d+/}
  69. 69. Regex Constraint get "/:id" => "posts#index", :id => /d+/
  70. 70. Request-Based Constraint get "/mobile" => "posts#index", :constraints => {:user_agent => /iPhone/}
  71. 71. Request-Based Constraint get "/mobile" => "posts#index", :constraints => {:user_agent => /iPhone/}, :defaults => {:mobile => true}
  72. 72. Request-Based Constraint get "/mobile" => "posts#index", :user_agent => /iPhone/, :mobile => true
  73. 73. Object Constraints class DubDubConstraint def self.matches?(request) request.host =~ /^(www.)/ end end get "/" => "posts#index", :constraints => DubDubConstraint
  74. 74. Rack
  75. 75. Equivalent get "/posts" => "posts#index" get "/posts" => PostsController.action(:index)
  76. 76. Rack >> a = PostsController.action(:index)
  77. 77. Rack >> a = PostsController.action(:index) => #<Proc:0x0000000103d050d0@/Users/ wycats/Code/rails/actionpack/lib/ action_controller/metal.rb:123>
  78. 78. Rack >> a = PostsController.action(:index) => #<Proc:0x0000000103d050d0@/Users/ wycats/Code/rails/actionpack/lib/ action_controller/metal.rb:123> >> e = Rack::MockRequest.env_for("/")
  79. 79. 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", ...}
  80. 80. 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)
  81. 81. 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"=> ‘"eca5953f36da05ff351d712d904ef28d"’, ...}
  82. 82. Match to Rack class MyApp def call(env) [200, {"Content-Type" => "text/html"}, ["Hello World"]] end end get "/" => MyApp
  83. 83. Redirection get "/" => redirect("/foo")
  84. 84. Redirection get "/" => redirect("/foo") get "/:id" => redirect("/posts/%{id}") get "/:id" => redirect("/posts/%s")
  85. 85. Redirection get "/" => redirect("/foo") get "/:id" => redirect("/posts/%{id}") get "/:id" => redirect("/posts/%s") get "/:id" => redirect { |params, req| ... }
  86. 86. 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
  87. 87. 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
  88. 88. 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
  89. 89. Resources
  90. 90. Resources resources :magazines do resources :ads end
  91. 91. Member Resources resources :photos do member do get :preview get :print end end
  92. 92. One-Offs resources :photos do get :preview, :on => :member end
  93. 93. Collections resources :photos do collection do get :search end end
  94. 94. Combination scope :module => "admin" do constraints IpBlacklist do resources :posts, :comments end end
  95. 95. ActiveRecord
  96. 96. New Chainable, Lazy API
  97. 97. Chainable Methods ★ select ★ order ★ from ★ limit ★ where ★ offset ★ joins ★ includes ★ having ★ lock ★ group ★ readonly
  98. 98. Controller def index @posts = Post. where(:published => true). order("publish_date desc") end
  99. 99. Model scope :published, where(:published => true). order("publish_date desc")
  100. 100. Model scope :desc, order("publish_date desc") scope :published, where(:published => true).desc
  101. 101. Controller def index @posts = Post. where("created_at < ?", Time.now). order("publish_date desc") end
  102. 102. Model scope :desc, order("publish_date desc") def self.past where("created_at < ?", Time.now).desc end
  103. 103. Model scope :desc, order("publish_date desc") def self.past where("created_at < ?", Time.now).desc end def self.recent(number) past.limit(5) end
  104. 104. Pagination class PostsController 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
  105. 105. named_scope with_scope nd(:all)
  106. 106. scope
  107. 107. ActionMailer
  108. 108. Massive API Overhaul
  109. 109. Sending Emails def welcome(user) @user = user mail(:to => user.email, :subject => "Welcome man!") end
  110. 110. welcome.text.erb welcome.html.erb
  111. 111. Layouts layout "rails_dispatch" def welcome(user) @user = user mail(:to => user.email, :subject => "Welcome man!") end
  112. 112. rails_dispatch.text.erb rails_dispatch.html.erb
  113. 113. 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
  114. 114. 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
  115. 115. Attachments def welcome(user) @user = user file = Rails.public_path.join("hello.pdf") contents = File.readfile) attachments["welcome.pdf"] = contents mail(:to => user.email, :subject => "Welcome man!") end
  116. 116. Interceptors class MyInterceptor def self.delivering_email(mail) original = mail.to mail.to = "wycats@gmail.com" mail.subject = "#{original}: #{mail.subject}" end end
  117. 117. 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)
  118. 118. Interceptors Delivery Observers
  119. 119. delivering_mail deliver delivered_mail
  120. 120. Bundler
  121. 121. gembundler.com
  122. 122. gembundler.com /rails3.html
  123. 123. railsdispatch.com /posts/bundler
  124. 124. yehudakatz.com/ 2010/04/12/some-of- the-problems- bundler-solves/
  125. 125. yehudakatz.com/ 2010/04/17/ruby- require-order- problems/
  126. 126. Choices
  127. 127. rspec-rails
  128. 128. generators rake tasks controller_example view_example request_example mailer_example
  129. 129. 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
  130. 130. dm-rails
  131. 131. generators rake tasks append_info_to_payload i18n_scope IdentityMap middleware
  132. 132. 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
  133. 133. 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
  134. 134. rails g $ rails g stylesheets Rails: DataMapper: controller data_mapper:migration generator data_mapper:model helper data_mapper:observer integration_test mailer Rspec: metal rspec:controller migration rspec:helper model rspec:install observer rspec:integration performance_test rspec:mailer plugin rspec:model resource rspec:observer scaffold rspec:scaffold scaffold_controller rspec:view session_migration

×