aboutsummaryrefslogtreecommitdiffstats
path: root/actionpack
diff options
context:
space:
mode:
Diffstat (limited to 'actionpack')
-rw-r--r--actionpack/lib/action_controller/integration.rb18
-rwxr-xr-xactionpack/lib/action_controller/response.rb48
-rw-r--r--actionpack/lib/action_controller/test_case.rb62
-rw-r--r--actionpack/lib/action_controller/test_process.rb9
-rw-r--r--actionpack/lib/action_controller/url_rewriter.rb97
5 files changed, 203 insertions, 31 deletions
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
- # (<tt>application/x-www-form-urlencoded</tt> or <tt>multipart/form-data</tt>).
- # 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
+ # (<tt>application/x-www-form-urlencoded</tt> or <tt>multipart/form-data</tt>).
+ # - +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 <tt>@response</tt>
+ # 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:
+ #
+ # <b>@controller</b>::
+ # The controller instance that will be tested.
+ # <b>@request</b>::
+ # 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.
+ # <b>@response</b>::
+ # An ActionController::TestResponse object, representing the response
+ # of the last HTTP response. In the above example, <tt>@response</tt> 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 <b>routes.rb</b> 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'
+ # <b>Tip:</b> 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 <tt>:only_path => true</tt> 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 <tt>:host</tt>
+ # 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 <tt>:host</tt>
+ # 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 <tt>:host</tt> 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
+ # <b>routes.rb</b>:
+ #
+ # map.resources :users
+ #
+ # This generates, among other things, the method <tt>users_path</tt>. 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 <tt>:host</tt>
# pair is provided.