Sie sind auf Seite 1von 139

{

Rails 3

Overview

A Lot Like Rails 2.3

Quick Refresher

What Hasnt Changed?

MVC

REST

Resources

Controllers

Migrations

AR Ideas

Big User-Facing Changes

File Structure

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

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

Gem le
source 'http://rubygems.org' gem 'rails', '3.0.0.beta3' gem 'sqlite3-ruby', :require => 'sqlite3'

con g/environment.rb
# Load the rails application require File.expand_path( '../application', __FILE__ ) # Initialize the rails application Tutorial::Application.initialize!

con g/application.rb (1)


require File.expand_path( '../boot', __FILE__ ) require 'rails/all' if defined?(Bundler) Bundler.require(:default, Rails.env) end

con g/application.rb (2)


module Tutorial class Application < Rails::Application config.encoding = "utf-8" config.filter_parameters += [:password] end end

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

initializers/session_store.rb
Rails.application. config.session_store( :cookie_store, :key => '_tutorial_session' )

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

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'

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

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>

public/ javascripts/ rails.js

github.com/ rails/jquery-ujs

db/seeds.rb

rake db:setup

db:create db:schema:load db:seed

lib/tasks/setup.rake
task :bundle do system "bundle install" end task :setup => ["bundle", "db:setup"]

Rails Command
generate console server
| g | c | s

destroy benchmarker profiler plugin runner

dbconsole | db application

Block Helpers

Block Helpers (Before)


<% form_for @post do |f| %> <% end %>

Block Helpers (Before)


<% box do %> <p>Hello World!</p> <% end %>

Block Helpers (Before)


def box(&block) content = "<div class='box'>" << capture(&block) << "</div>" if block_called_from_erb? concat(content) else content end end

Block Helpers (After)


<%= box do %> <p>Hello World!</p> <% end %>

Block Helpers (After)


def box(&block) "<div class='box'>" \ "#{capture(&block)}" \ "</div>" end

Block Helpers (After)


def box(&block) "<div class='box'>" \ "#{capture(&block)}" \ "</div>".html_safe end

Router

Note: Signi cant Changes Ahead

Also Note: Old Mapper Still Available

Matching
map.connect "posts", :controller => :posts, :action => :index

Matching
map.connect "posts", :controller => :posts, :action => :index match "posts" => "posts#index"

Matching
map.connect "posts", :controller => :posts, :action => :index match "/posts" => "posts#index"

Optional Segments
match "/posts(/page)" => "posts#index"

Optional Dynamic Segments


match "/posts(/:id)" => "posts#index"

Default Parameters
match "/posts(/:id)" => "posts#index", :defaults => {:id => 1}

Default Parameters
match "/posts(/:id)" => "posts#index", :id => 1

Named Routes
match "/posts(/:id)" => "posts#index", :id => 1, :as => "posts"

The Root
root :to => "posts#index"

Scopes

Path Scope
match "/admin/posts" => "posts#index" match "/admin/users" => "users#index"

Path Scope
scope :path => "admin" do match "/posts" => "posts#index" match "/users" => "users#index" end

Path Scope
scope "admin" do match "/posts" => "posts#index" match "/users" => "users#index" end

Module Scope
match "/posts" => "admin/posts#index" match "/users" => "admin/users#index"

Module Scope
scope :module => "admin" do match "/posts" => "posts#index" match "/users" => "users#index" end

Both
match "admin/posts" => "admin/posts#index" match "admin/users" => "admin/users#index"

Both
namespace "admin" do match "/posts" => "posts#index" match "/users" => "users#index" end

HTTP Methods

Get Request
match "/posts" => "posts#index", :via => "get"

Get Request
get "/posts" => "posts#index"

Scoping
scope "/posts" do controller :posts do get "/" => :index end end

Scoping
get "/posts" => "posts#index"

Default Resource Route


controller :posts do scope "/posts" do get "/" post "/" get "/:id" put "/:id" delete "/:id" get get end end "/new" "/:id/edit" => => => => => :index :create :show :update :delete

=> :new => :edit

Default Resource Route


controller :posts do scope "/posts" do get "/" post "/" get "/:id" put "/:id" delete "/:id" get get end end "/new" "/:id/edit" => => => => => :index, :create :show, :update :delete :as => :posts :as => :post

=> :new, => :edit,

:as => :new_post :as => :edit_post

Constraints

Regex Constraint
get "/:id" => "posts#index", :constraints => {:id => /\d+/}

Regex Constraint
get "/:id" => "posts#index", :id => /\d+/

Request-Based Constraint
get "/mobile" => "posts#index", :constraints => {:user_agent => /iPhone/}

Request-Based Constraint
get "/mobile" => "posts#index", :constraints => {:user_agent => /iPhone/}, :defaults => {:mobile => true}

Request-Based Constraint
get "/mobile" => "posts#index", :user_agent => /iPhone/, :mobile => true

Object Constraints
class DubDubConstraint def self.matches?(request) request.host =~ /^(www\.)/ end end get "/" => "posts#index", :constraints => DubDubConstraint

Rack

Equivalent
get "/posts" => "posts#index" get "/posts" => PostsController.action(:index)

Rack
>> a = PostsController.action(:index)

Rack
>> a = PostsController.action(:index) => #<Proc:0x0000000103d050d0@/Users/ wycats/Code/rails/actionpack/lib/ action_controller/metal.rb:123>

Rack
>> a = PostsController.action(:index) => #<Proc:0x0000000103d050d0@/Users/ wycats/Code/rails/actionpack/lib/ action_controller/metal.rb:123> >> e = Rack::MockRequest.env_for("/")

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", ...}

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)

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", ...}

Match to Rack
class MyApp def call(env) [200, {"Content-Type" => "text/html"}, ["Hello World"]] end end get "/" => MyApp

Redirection
get "/" => redirect("/foo")

Redirection
get "/" => redirect("/foo") get "/:id" => redirect("/posts/%{id}") get "/:id" => redirect("/posts/%s")

Redirection
get "/" => redirect("/foo") get "/:id" => redirect("/posts/%{id}") get "/:id" => redirect("/posts/%s") get "/:id" => redirect { |params, req| ... }

Rack App
def redirect(*args, &block) options = args.last.is_a?(Hash) ? args.pop : {} path path_proc status body = = = = args.shift || block path.is_a?(Proc) ? path : proc { |params| path % params } options[:status] || 301 '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

Rack App
def redirect(*args, &block) options = args.last.is_a?(Hash) ? args.pop : {} path path_proc status body = = = = args.shift || block path.is_a?(Proc) ? path : proc { |params| path % params } options[:status] || 301 'Moved Permanently'

lambda do |env| req = Request.new(env)

params = [req.symbolized_path_parameters] params << req if path_proc.arity > 1

redirect(*args, &block)

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

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

Resources

Resources
resources :magazines do resources :ads end

Member Resources
resources :photos do member do get :preview get :print end end

One-Os
resources :photos do get :preview, :on => :member end

Collections
resources :photos do collection do get :search end end

Combination
scope :module => "admin" do constraints IpBlacklist do resources :posts, :comments end end

ActiveRecord

New Chainable, Lazy API

Chainable Methods
select from where joins having group order limit offset includes lock readonly

Controller
def index @posts = Post. where(:published => true). order("publish_date desc") end

Model
scope :published, where(:published => true). order("publish_date desc")

Model
scope :desc, order("publish_date desc") scope :published, where(:published => true).desc

Controller
def index @posts = Post. where("created_at < ?", Time.now). order("publish_date desc") end

Model
scope :desc, order("publish_date desc") def self.past where("created_at < ?", Time.now).desc end

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

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

named_scope with_scope nd(:all)

scope

ActionMailer

Massive API Overhaul

Sending Emails
def welcome(user) @user = user mail(:to => user.email, :subject => "Welcome man!") end

welcome.text.erb welcome.html.erb

Layouts
layout "rails_dispatch" def welcome(user) @user = user mail(:to => user.email, :subject => "Welcome man!") end

rails_dispatch.text.erb rails_dispatch.html.erb

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

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

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

Interceptors
class MyInterceptor def self.delivering_email(mail) original = mail.to mail.to = "wycats@gmail.com" mail.subject = "#{original}: #{mail.subject}" end end

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)

Interceptors Delivery Observers

delivering_mail deliver delivered_mail

Bundler

gembundler.com

gembundler.com /rails3.html

railsdispatch.com /posts/bundler

yehudakatz.com/ 2010/04/12/some-ofthe-problemsbundler-solves/

yehudakatz.com/ 2010/04/17/rubyrequire-orderproblems/

Choices

rspec-rails

generators rake tasks controller_example view_example request_example mailer_example

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

dm-rails

generators rake tasks append_info_to_payload i18n_scope IdentityMap middleware

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

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

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 DataMapper: data_mapper:migration data_mapper:model data_mapper:observer Rspec: rspec:controller rspec:helper rspec:install rspec:integration rspec:mailer rspec:model rspec:observer rspec:scaffold rspec:view

Das könnte Ihnen auch gefallen