From 6e754551254a8cc64e034163f5d0dc155b450388 Mon Sep 17 00:00:00 2001 From: Pratik Naik Date: Mon, 28 Jul 2008 12:26:59 +0100 Subject: Merge docrails changes --- actionpack/lib/action_controller/integration.rb | 18 +++-- actionpack/lib/action_controller/response.rb | 48 +++++++++++- actionpack/lib/action_controller/test_case.rb | 62 ++++++++++++--- actionpack/lib/action_controller/test_process.rb | 9 ++- actionpack/lib/action_controller/url_rewriter.rb | 97 +++++++++++++++++++++--- 5 files changed, 203 insertions(+), 31 deletions(-) (limited to 'actionpack/lib/action_controller') diff --git a/actionpack/lib/action_controller/integration.rb b/actionpack/lib/action_controller/integration.rb index 2a732448f2..43158ea412 100644 --- a/actionpack/lib/action_controller/integration.rb +++ b/actionpack/lib/action_controller/integration.rb @@ -165,11 +165,19 @@ module ActionController status/100 == 3 end - # Performs a GET request with the given parameters. The parameters may - # be +nil+, a Hash, or a string that is appropriately encoded - # (application/x-www-form-urlencoded or multipart/form-data). - # The headers should be a hash. The keys will automatically be upcased, with the - # prefix 'HTTP_' added if needed. + # Performs a GET request with the given parameters. + # + # - +path+: The URI (as a String) on which you want to perform a GET request. + # - +parameters+: The HTTP parameters that you want to pass. This may be +nil+, + # a Hash, or a String that is appropriately encoded + # (application/x-www-form-urlencoded or multipart/form-data). + # - +headers+: Additional HTTP headers to pass, as a Hash. The keys will + # automatically be upcased, with the prefix 'HTTP_' added if needed. + # + # This method returns an AbstractResponse object, which one can use to inspect + # the details of the response. Furthermore, if this method was called from an + # ActionController::IntegrationTest object, then that object's @response + # instance variable will point to the same response object. # # You can also perform POST, PUT, DELETE, and HEAD requests with +post+, # +put+, +delete+, and +head+. diff --git a/actionpack/lib/action_controller/response.rb b/actionpack/lib/action_controller/response.rb index 9955532844..da352b6993 100755 --- a/actionpack/lib/action_controller/response.rb +++ b/actionpack/lib/action_controller/response.rb @@ -1,19 +1,61 @@ require 'digest/md5' -module ActionController - class AbstractResponse #:nodoc: +module ActionController # :nodoc: + # Represents an HTTP response generated by a controller action. One can use an + # ActionController::AbstractResponse object to retrieve the current state of the + # response, or customize the response. An AbstractResponse object can either + # represent a "real" HTTP response (i.e. one that is meant to be sent back to the + # web browser) or a test response (i.e. one that is generated from integration + # tests). See CgiResponse and TestResponse, respectively. + # + # AbstractResponse is mostly a Ruby on Rails framework implement detail, and should + # never be used directly in controllers. Controllers should use the methods defined + # in ActionController::Base instead. For example, if you want to set the HTTP + # response's content MIME type, then use ActionControllerBase#headers instead of + # AbstractResponse#headers. + # + # Nevertheless, integration tests may want to inspect controller responses in more + # detail, and that's when AbstractResponse can be useful for application developers. + # Integration test methods such as ActionController::Integration::Session#get and + # ActionController::Integration::Session#post return objects of type TestResponse + # (which are of course also of type AbstractResponse). + # + # For example, the following demo integration "test" prints the body of the + # controller response to the console: + # + # class DemoControllerTest < ActionController::IntegrationTest + # def test_print_root_path_to_console + # get('/') + # puts @response.body + # end + # end + class AbstractResponse DEFAULT_HEADERS = { "Cache-Control" => "no-cache" } attr_accessor :request - attr_accessor :body, :headers, :session, :cookies, :assigns, :template, :redirected_to, :redirected_to_method_params, :layout + + # The body content (e.g. HTML) of the response, as a String. + attr_accessor :body + # The headers of the response, as a Hash. It maps header names to header values. + attr_accessor :headers + attr_accessor :session, :cookies, :assigns, :template, :redirected_to, :redirected_to_method_params, :layout def initialize @body, @headers, @session, @assigns = "", DEFAULT_HEADERS.merge("cookie" => []), [], [] end + # Sets the HTTP response's content MIME type. For example, in the controller + # you could write this: + # + # response.content_type = "text/plain" + # + # If a character set has been defined for this response (see charset=) then + # the character set information will also be included in the content type + # information. def content_type=(mime_type) self.headers["Content-Type"] = charset ? "#{mime_type}; charset=#{charset}" : mime_type end + # Returns the response's content MIME type, or nil if content type has been set. def content_type content_type = String(headers["Content-Type"] || headers["type"]).split(";")[0] content_type.blank? ? nil : content_type diff --git a/actionpack/lib/action_controller/test_case.rb b/actionpack/lib/action_controller/test_case.rb index c09050c390..3e66947d5f 100644 --- a/actionpack/lib/action_controller/test_case.rb +++ b/actionpack/lib/action_controller/test_case.rb @@ -15,23 +15,61 @@ module ActionController end end - # Superclass for Action Controller functional tests. Infers the controller under test from the test class name, - # and creates @controller, @request, @response instance variables. + # Superclass for ActionController functional tests. Functional tests allow you to + # test a single controller action per test method. This should not be confused with + # integration tests (see ActionController::IntegrationTest), which are more like + # "stories" that can involve multiple controllers and mutliple actions (i.e. multiple + # different HTTP requests). # - # class WidgetsControllerTest < ActionController::TestCase - # def test_index - # get :index + # == Basic example + # + # Functional tests are written as follows: + # 1. First, one uses the +get+, +post+, +put+, +delete+ or +head+ method to simulate + # an HTTP request. + # 2. Then, one asserts whether the current state is as expected. "State" can be anything: + # the controller's HTTP response, the database contents, etc. + # + # For example: + # + # class BooksControllerTest < ActionController::TestCase + # def test_create + # # Simulate a POST response with the given HTTP parameters. + # post(:create, :book => { :title => "Love Hina" }) + # + # # Assert that the controller tried to redirect us to + # # the created book's URI. + # assert_response :found + # + # # Assert that the controller really put the book in the database. + # assert_not_nil Book.find_by_title("Love Hina") # end # end # - # * @controller - WidgetController.new - # * @request - ActionController::TestRequest.new - # * @response - ActionController::TestResponse.new + # == Special instance variables + # + # ActionController::TestCase will also automatically provide the following instance + # variables for use in the tests: + # + # @controller:: + # The controller instance that will be tested. + # @request:: + # An ActionController::TestRequest, representing the current HTTP + # request. You can modify this object before sending the HTTP request. For example, + # you might want to set some session properties before sending a GET request. + # @response:: + # An ActionController::TestResponse object, representing the response + # of the last HTTP response. In the above example, @response becomes valid + # after calling +post+. If the various assert methods are not sufficient, then you + # may use this object to inspect the HTTP response in detail. + # + # (Earlier versions of Rails required each functional test to subclass + # Test::Unit::TestCase and define @controller, @request, @response in +setup+.) # - # (Earlier versions of Rails required each functional test to subclass Test::Unit::TestCase and define - # @controller, @request, @response in +setup+.) + # == Controller is automatically inferred # - # If the controller cannot be inferred from the test class name, you can explicity set it with +tests+. + # ActionController::TestCase will automatically infer the controller under test + # from the test class name. If the controller cannot be inferred from the test + # class name, you can explicity set it with +tests+. # # class SpecialEdgeCaseWidgetsControllerTest < ActionController::TestCase # tests WidgetController @@ -103,4 +141,4 @@ module ActionController @request.remote_addr = '208.77.188.166' # example.com end end -end \ No newline at end of file +end diff --git a/actionpack/lib/action_controller/test_process.rb b/actionpack/lib/action_controller/test_process.rb index 721592b81f..66675aaa13 100644 --- a/actionpack/lib/action_controller/test_process.rb +++ b/actionpack/lib/action_controller/test_process.rb @@ -266,7 +266,13 @@ module ActionController #:nodoc: end end - class TestResponse < AbstractResponse #:nodoc: + # Integration test methods such as ActionController::Integration::Session#get + # and ActionController::Integration::Session#post return objects of class + # TestResponse, which represent the HTTP response results of the requested + # controller actions. + # + # See AbstractResponse for more information on controller response objects. + class TestResponse < AbstractResponse include TestResponseBehavior end @@ -348,6 +354,7 @@ module ActionController #:nodoc: module TestProcess def self.included(base) # execute the request simulating a specific HTTP method and set/volley the response + # TODO: this should be un-DRY'ed for the sake of API documentation. %w( get post put delete head ).each do |method| base.class_eval <<-EOV, __FILE__, __LINE__ def #{method}(action, parameters = nil, session = nil, flash = nil) diff --git a/actionpack/lib/action_controller/url_rewriter.rb b/actionpack/lib/action_controller/url_rewriter.rb index d0bf6c0bd4..d86e2db67d 100644 --- a/actionpack/lib/action_controller/url_rewriter.rb +++ b/actionpack/lib/action_controller/url_rewriter.rb @@ -1,19 +1,96 @@ module ActionController - # Write URLs from arbitrary places in your codebase, such as your mailers. + # In routes.rb one defines URL-to-controller mappings, but the reverse + # is also possible: an URL can be generated from one of your routing definitions. + # URL generation functionality is centralized in this module. # - # Example: + # See ActionController::Routing and ActionController::Resources for general + # information about routing and routes.rb. # - # class MyMailer - # include ActionController::UrlWriter - # default_url_options[:host] = 'www.basecamphq.com' + # Tip: If you need to generate URLs from your models or some other place, + # then ActionController::UrlWriter is what you're looking for. Read on for + # an introduction. # - # def signup_url(token) - # url_for(:controller => 'signup', action => 'index', :token => token) + # == URL generation from parameters + # + # As you may know, some functions - such as ActionController::Base#url_for + # and ActionView::Helpers::UrlHelper#link_to, can generate URLs given a set + # of parameters. For example, you've probably had the chance to write code + # like this in one of your views: + # + # <%= link_to('Click here', :controller => 'users', + # :action => 'new', :message => 'Welcome!') %> + # + # #=> Generates a link to: /users/new?message=Welcome%21 + # + # link_to, and all other functions that require URL generation functionality, + # actually use ActionController::UrlWriter under the hood. And in particular, + # they use the ActionController::UrlWriter#url_for method. One can generate + # the same path as the above example by using the following code: + # + # include UrlWriter + # url_for(:controller => 'users', + # :action => 'new', + # :message => 'Welcome!', + # :only_path => true) + # # => "/users/new?message=Welcome%21" + # + # Notice the :only_path => true part. This is because UrlWriter has no + # information about the website hostname that your Rails app is serving. So if you + # want to include the hostname as well, then you must also pass the :host + # argument: + # + # include UrlWriter + # url_for(:controller => 'users', + # :action => 'new', + # :message => 'Welcome!', + # :host => 'www.example.com') # Changed this. + # # => "http://www.example.com/users/new?message=Welcome%21" + # + # By default, all controllers and views have access to a special version of url_for, + # that already knows what the current hostname is. So if you use url_for in your + # controllers or your views, then you don't need to explicitly pass the :host + # argument. + # + # For convenience reasons, mailers provide a shortcut for ActionController::UrlWriter#url_for. + # So within mailers, you only have to type 'url_for' instead of 'ActionController::UrlWriter#url_for' + # in full. However, mailers don't have hostname information, and what's why you'll still + # have to specify the :host argument when generating URLs in mailers. + # + # + # == URL generation for named routes + # + # UrlWriter also allows one to access methods that have been auto-generated from + # named routes. For example, suppose that you have a 'users' resource in your + # routes.rb: + # + # map.resources :users + # + # This generates, among other things, the method users_path. By default, + # this method is accessible from your controllers, views and mailers. If you need + # to access this auto-generated method from other places (such as a model), then + # you can do that in two ways. + # + # The first way is to include ActionController::UrlWriter in your class: + # + # class User < ActiveRecord::Base + # include ActionController::UrlWriter # !!! + # + # def name=(value) + # write_attribute('name', value) + # write_attribute('base_uri', users_path) # !!! # end - # end + # end # - # In addition to providing +url_for+, named routes are also accessible after - # including UrlWriter. + # The second way is to access them through ActionController::UrlWriter. + # The autogenerated named routes methods are available as class methods: + # + # class User < ActiveRecord::Base + # def name=(value) + # write_attribute('name', value) + # path = ActionController::UrlWriter.users_path # !!! + # write_attribute('base_uri', path) # !!! + # end + # end module UrlWriter # The default options for urls written by this writer. Typically a :host # pair is provided. -- cgit v1.2.3