diff options
author | Pratik Naik <pratiknaik@gmail.com> | 2008-10-05 19:46:48 +0100 |
---|---|---|
committer | Pratik Naik <pratiknaik@gmail.com> | 2008-10-05 19:46:48 +0100 |
commit | 6090513cfb8acb5554a6653a6f2cb87648585d41 (patch) | |
tree | 99bfd589a48153e33f19ae72baa6e98f5708a9b8 /actionpack | |
parent | 01159a6431bbc2dc7d7d95ce294c8567c954f39e (diff) | |
parent | 4df45d86097efbeabceecfe53d8ea2da9ccbb107 (diff) | |
download | rails-6090513cfb8acb5554a6653a6f2cb87648585d41.tar.gz rails-6090513cfb8acb5554a6653a6f2cb87648585d41.tar.bz2 rails-6090513cfb8acb5554a6653a6f2cb87648585d41.zip |
Merge commit 'mainstream/master'
Conflicts:
activerecord/lib/active_record/association_preload.rb
Diffstat (limited to 'actionpack')
-rw-r--r-- | actionpack/lib/action_controller/base.rb | 19 | ||||
-rw-r--r-- | actionpack/lib/action_controller/dispatcher.rb | 30 | ||||
-rw-r--r-- | actionpack/lib/action_controller/integration.rb | 2 | ||||
-rwxr-xr-x | actionpack/lib/action_controller/request.rb | 5 | ||||
-rw-r--r-- | actionpack/lib/action_controller/rescue.rb | 130 | ||||
-rw-r--r-- | actionpack/lib/action_controller/test_case.rb | 2 | ||||
-rw-r--r-- | actionpack/lib/action_view/base.rb | 18 | ||||
-rw-r--r-- | actionpack/lib/action_view/helpers/form_tag_helper.rb | 10 | ||||
-rw-r--r-- | actionpack/test/abstract_unit.rb | 2 | ||||
-rw-r--r-- | actionpack/test/controller/render_test.rb | 41 | ||||
-rw-r--r-- | actionpack/test/controller/rescue_test.rb | 35 | ||||
-rw-r--r-- | actionpack/test/template/form_tag_helper_test.rb | 6 |
12 files changed, 133 insertions, 167 deletions
diff --git a/actionpack/lib/action_controller/base.rb b/actionpack/lib/action_controller/base.rb index 91f531f12c..413f6d48e5 100644 --- a/actionpack/lib/action_controller/base.rb +++ b/actionpack/lib/action_controller/base.rb @@ -290,8 +290,6 @@ module ActionController #:nodoc: @@allow_concurrency = false cattr_accessor :allow_concurrency - @@guard = Monitor.new - # Modern REST web services often need to submit complex data to the web application. # The <tt>@@param_parsers</tt> hash lets you register handlers which will process the HTTP body and add parameters to the # <tt>params</tt> hash. These handlers are invoked for POST and PUT requests. @@ -532,12 +530,7 @@ module ActionController #:nodoc: assign_names log_processing - - if @@allow_concurrency - send(method, *arguments) - else - @@guard.synchronize { send(method, *arguments) } - end + send(method, *arguments) send_response ensure @@ -975,13 +968,15 @@ module ActionController #:nodoc: # Sets the Last-Modified response header. Returns 304 Not Modified if the # If-Modified-Since request header is <= last modified. def last_modified!(utc_time) - head(:not_modified) if response.last_modified!(utc_time) + response.last_modified= utc_time + head(:not_modified) if response.last_modified == request.if_modified_since end # Sets the ETag response header. Returns 304 Not Modified if the # If-None-Match request header matches. def etag!(etag) - head(:not_modified) if response.etag!(etag) + response.etag = etag + head(:not_modified) if response.etag == request.if_none_match end # Clears the rendered results, allowing for another render to be performed. @@ -1256,7 +1251,7 @@ module ActionController #:nodoc: action_name = strip_out_controller(action_name) end end - "#{self.class.controller_path}/#{action_name}" + "#{self.controller_path}/#{action_name}" end def strip_out_controller(path) @@ -1264,7 +1259,7 @@ module ActionController #:nodoc: end def template_path_includes_controller?(path) - self.class.controller_path.split('/')[-1] == path.split('/')[0] + self.controller_path.split('/')[-1] == path.split('/')[0] end def process_cleanup diff --git a/actionpack/lib/action_controller/dispatcher.rb b/actionpack/lib/action_controller/dispatcher.rb index bdae5f9d86..90c8400c11 100644 --- a/actionpack/lib/action_controller/dispatcher.rb +++ b/actionpack/lib/action_controller/dispatcher.rb @@ -2,6 +2,8 @@ module ActionController # Dispatches requests to the appropriate controller and takes care of # reloading the app after each request when Dependencies.load? is true. class Dispatcher + @@guard = Mutex.new + class << self def define_dispatcher_callbacks(cache_classes) unless cache_classes @@ -20,6 +22,7 @@ module ActionController end if defined?(ActiveRecord) + after_dispatch :checkin_connections before_dispatch { ActiveRecord::Base.verify_active_connections! } to_prepare(:activerecord_instantiate_observers) { ActiveRecord::Base.instantiate_observers } end @@ -98,7 +101,7 @@ module ActionController @output, @request, @response = output, request, response end - def dispatch + def dispatch_unlocked begin run_callbacks :before_dispatch handle_request @@ -109,6 +112,16 @@ module ActionController end end + def dispatch + if ActionController::Base.allow_concurrency + dispatch_unlocked + else + @@guard.synchronize do + dispatch_unlocked + end + end + end + def dispatch_cgi(cgi, session_options) if cgi ||= self.class.failsafe_response(@output, '400 Bad Request') { CGI.new } @request = CgiRequest.new(cgi, session_options) @@ -145,6 +158,21 @@ module ActionController Base.logger.flush end + def mark_as_test_request! + @test_request = true + self + end + + def test_request? + @test_request + end + + def checkin_connections + # Don't return connection (and peform implicit rollback) if this request is a part of integration test + return if test_request? + ActiveRecord::Base.clear_active_connections! + end + protected def handle_request @controller = Routing::Routes.recognize(@request) diff --git a/actionpack/lib/action_controller/integration.rb b/actionpack/lib/action_controller/integration.rb index a98c1af7f9..fc473c269c 100644 --- a/actionpack/lib/action_controller/integration.rb +++ b/actionpack/lib/action_controller/integration.rb @@ -276,7 +276,7 @@ module ActionController ActionController::Base.clear_last_instantiation! env['rack.input'] = data.is_a?(IO) ? data : StringIO.new(data || '') - @status, @headers, result_body = ActionController::Dispatcher.new.call(env) + @status, @headers, result_body = ActionController::Dispatcher.new.mark_as_test_request!.call(env) @request_count += 1 @controller = ActionController::Base.last_instantiation diff --git a/actionpack/lib/action_controller/request.rb b/actionpack/lib/action_controller/request.rb index 8e6cfb41dc..5e492e3ee1 100755 --- a/actionpack/lib/action_controller/request.rb +++ b/actionpack/lib/action_controller/request.rb @@ -167,7 +167,7 @@ module ActionController parameter_format = parameters[:format] if parameter_format - parameter_format.to_sym + parameter_format elsif xhr? :js else @@ -176,8 +176,7 @@ module ActionController end def cache_format - parameter_format = parameters[:format] - parameter_format && parameter_format.to_sym + parameters[:format] end # Returns true if the request's "X-Requested-With" header contains diff --git a/actionpack/lib/action_controller/rescue.rb b/actionpack/lib/action_controller/rescue.rb index 83c4218af4..ec8e9b92d5 100644 --- a/actionpack/lib/action_controller/rescue.rb +++ b/actionpack/lib/action_controller/rescue.rb @@ -41,10 +41,9 @@ module ActionController #:nodoc: base.rescue_templates = Hash.new(DEFAULT_RESCUE_TEMPLATE) base.rescue_templates.update DEFAULT_RESCUE_TEMPLATES - base.class_inheritable_array :rescue_handlers - base.rescue_handlers = [] - base.extend(ClassMethods) + base.send :include, ActiveSupport::Rescuable + base.class_eval do alias_method_chain :perform_action, :rescue end @@ -54,82 +53,12 @@ module ActionController #:nodoc: def process_with_exception(request, response, exception) #:nodoc: new.process(request, response, :rescue_action, exception) end - - # Rescue exceptions raised in controller actions. - # - # <tt>rescue_from</tt> receives a series of exception classes or class - # names, and a trailing <tt>:with</tt> option with the name of a method - # or a Proc object to be called to handle them. Alternatively a block can - # be given. - # - # Handlers that take one argument will be called with the exception, so - # that the exception can be inspected when dealing with it. - # - # Handlers are inherited. They are searched from right to left, from - # bottom to top, and up the hierarchy. The handler of the first class for - # which <tt>exception.is_a?(klass)</tt> holds true is the one invoked, if - # any. - # - # class ApplicationController < ActionController::Base - # rescue_from User::NotAuthorized, :with => :deny_access # self defined exception - # rescue_from ActiveRecord::RecordInvalid, :with => :show_errors - # - # rescue_from 'MyAppError::Base' do |exception| - # render :xml => exception, :status => 500 - # end - # - # protected - # def deny_access - # ... - # end - # - # def show_errors(exception) - # exception.record.new_record? ? ... - # end - # end - def rescue_from(*klasses, &block) - options = klasses.extract_options! - unless options.has_key?(:with) - block_given? ? options[:with] = block : raise(ArgumentError, "Need a handler. Supply an options hash that has a :with key as the last argument.") - end - - klasses.each do |klass| - key = if klass.is_a?(Class) && klass <= Exception - klass.name - elsif klass.is_a?(String) - klass - else - raise(ArgumentError, "#{klass} is neither an Exception nor a String") - end - - # Order is important, we put the pair at the end. When dealing with an - # exception we will follow the documented order going from right to left. - rescue_handlers << [key, options[:with]] - end - end end protected # Exception handler called when the performance of an action raises an exception. def rescue_action(exception) - if handler_for_rescue(exception) - rescue_action_with_handler(exception) - else - log_error(exception) if logger - erase_results if performed? - - # Let the exception alter the response if it wants. - # For example, MethodNotAllowed sets the Allow header. - if exception.respond_to?(:handle_response!) - exception.handle_response!(response) - end - - if consider_all_requests_local || local_request? - rescue_action_locally(exception) - else - rescue_action_in_public(exception) - end - end + rescue_with_handler(exception) || rescue_action_without_handler(exception) end # Overwrite to implement custom logging of errors. By default logs as fatal. @@ -185,15 +114,20 @@ module ActionController #:nodoc: render_for_file(rescues_path("layout"), response_code_for_rescue(exception)) end - # Tries to rescue the exception by looking up and calling a registered handler. - def rescue_action_with_handler(exception) - if handler = handler_for_rescue(exception) - if handler.arity != 0 - handler.call(exception) - else - handler.call - end - true # don't rely on the return value of the handler + def rescue_action_without_handler(exception) + log_error(exception) if logger + erase_results if performed? + + # Let the exception alter the response if it wants. + # For example, MethodNotAllowed sets the Allow header. + if exception.respond_to?(:handle_response!) + exception.handle_response!(response) + end + + if consider_all_requests_local || local_request? + rescue_action_locally(exception) + else + rescue_action_in_public(exception) end end @@ -216,36 +150,6 @@ module ActionController #:nodoc: rescue_responses[exception.class.name] end - def handler_for_rescue(exception) - # We go from right to left because pairs are pushed onto rescue_handlers - # as rescue_from declarations are found. - _, handler = *rescue_handlers.reverse.detect do |klass_name, handler| - # The purpose of allowing strings in rescue_from is to support the - # declaration of handler associations for exception classes whose - # definition is yet unknown. - # - # Since this loop needs the constants it would be inconsistent to - # assume they should exist at this point. An early raised exception - # could trigger some other handler and the array could include - # precisely a string whose corresponding constant has not yet been - # seen. This is why we are tolerant to unknown constants. - # - # Note that this tolerance only matters if the exception was given as - # a string, otherwise a NameError will be raised by the interpreter - # itself when rescue_from CONSTANT is executed. - klass = self.class.const_get(klass_name) rescue nil - klass ||= klass_name.constantize rescue nil - exception.is_a?(klass) if klass - end - - case handler - when Symbol - method(handler) - when Proc - handler.bind(self) - end - end - def clean_backtrace(exception) if backtrace = exception.backtrace if defined?(RAILS_ROOT) diff --git a/actionpack/lib/action_controller/test_case.rb b/actionpack/lib/action_controller/test_case.rb index 3e66947d5f..6a39039504 100644 --- a/actionpack/lib/action_controller/test_case.rb +++ b/actionpack/lib/action_controller/test_case.rb @@ -84,7 +84,7 @@ module ActionController module RaiseActionExceptions attr_accessor :exception - def rescue_action(e) + def rescue_action_without_handler(e) self.exception = e if request.remote_addr == "0.0.0.0" diff --git a/actionpack/lib/action_view/base.rb b/actionpack/lib/action_view/base.rb index 8c00670087..8df10c40cc 100644 --- a/actionpack/lib/action_view/base.rb +++ b/actionpack/lib/action_view/base.rb @@ -290,21 +290,23 @@ module ActionView #:nodoc: private attr_accessor :_first_render, :_last_render - # Evaluate the local assigns and pushes them to the view. + # Evaluates the local assigns and controller ivars, pushes them to the view. def _evaluate_assigns_and_ivars #:nodoc: unless @assigns_added @assigns.each { |key, value| instance_variable_set("@#{key}", value) } - - if @controller - variables = @controller.instance_variables - variables -= @controller.protected_instance_variables if @controller.respond_to?(:protected_instance_variables) - variables.each {|name| instance_variable_set(name, @controller.instance_variable_get(name)) } - end - + _copy_ivars_from_controller @assigns_added = true end end + def _copy_ivars_from_controller #:nodoc: + if @controller + variables = @controller.instance_variable_names + variables -= @controller.protected_instance_variables if @controller.respond_to?(:protected_instance_variables) + variables.each { |name| instance_variable_set(name, @controller.instance_variable_get(name)) } + end + end + def _set_controller_content_type(content_type) #:nodoc: if controller.respond_to?(:response) controller.response.content_type ||= content_type diff --git a/actionpack/lib/action_view/helpers/form_tag_helper.rb b/actionpack/lib/action_view/helpers/form_tag_helper.rb index 294c22521e..208bf91dd4 100644 --- a/actionpack/lib/action_view/helpers/form_tag_helper.rb +++ b/actionpack/lib/action_view/helpers/form_tag_helper.rb @@ -403,6 +403,7 @@ module ActionView # Creates a field set for grouping HTML form elements. # # <tt>legend</tt> will become the fieldset's title (optional as per W3C). + # <tt>options</tt> accept the same values as tag. # # === Examples # <% field_set_tag do %> @@ -414,9 +415,14 @@ module ActionView # <p><%= text_field_tag 'name' %></p> # <% end %> # # => <fieldset><legend>Your details</legend><p><input id="name" name="name" type="text" /></p></fieldset> - def field_set_tag(legend = nil, &block) + # + # <% field_set_tag nil, :class => 'format' do %> + # <p><%= text_field_tag 'name' %></p> + # <% end %> + # # => <fieldset class="format"><p><input id="name" name="name" type="text" /></p></fieldset> + def field_set_tag(legend = nil, options = nil, &block) content = capture(&block) - concat(tag(:fieldset, {}, true)) + concat(tag(:fieldset, options, true)) concat(content_tag(:legend, legend)) unless legend.blank? concat(content) concat("</fieldset>") diff --git a/actionpack/test/abstract_unit.rb b/actionpack/test/abstract_unit.rb index 9db4cddd6a..673efa6af0 100644 --- a/actionpack/test/abstract_unit.rb +++ b/actionpack/test/abstract_unit.rb @@ -1,5 +1,5 @@ $:.unshift(File.dirname(__FILE__) + '/../lib') -$:.unshift(File.dirname(__FILE__) + '/../../activesupport/lib/active_support') +$:.unshift(File.dirname(__FILE__) + '/../../activesupport/lib') $:.unshift(File.dirname(__FILE__) + '/fixtures/helpers') require 'yaml' diff --git a/actionpack/test/controller/render_test.rb b/actionpack/test/controller/render_test.rb index af7b5dde62..5a6ca98b2e 100644 --- a/actionpack/test/controller/render_test.rb +++ b/actionpack/test/controller/render_test.rb @@ -39,6 +39,16 @@ class TestController < ActionController::Base render :action => 'hello_world' end end + + def conditional_hello_with_bangs + render :action => 'hello_world' + end + before_filter :handle_last_modified_and_etags, :only=>:conditional_hello_with_bangs + + def handle_last_modified_and_etags + last_modified! Time.now.utc.beginning_of_day + etag! [:foo, 123] + end def render_hello_world render :template => "test/hello_world" @@ -1306,6 +1316,7 @@ class EtagRenderTest < Test::Unit::TestCase @controller = TestController.new @request.host = "www.nextangle.com" + @expected_bang_etag = etag_for(expand_key([:foo, 123])) end def test_render_200_should_set_etag @@ -1365,11 +1376,27 @@ class EtagRenderTest < Test::Unit::TestCase assert_equal "<wrapper>\n<html>\n <p>Hello </p>\n<p>This is grand!</p>\n</html>\n</wrapper>\n", @response.body assert_equal etag_for("<wrapper>\n<html>\n <p>Hello </p>\n<p>This is grand!</p>\n</html>\n</wrapper>\n"), @response.headers['ETag'] end - + + def test_etag_with_bang_should_set_etag + get :conditional_hello_with_bangs + assert_equal @expected_bang_etag, @response.headers["ETag"] + assert_response :success + end + + def test_etag_with_bang_should_obey_if_none_match + @request.if_none_match = @expected_bang_etag + get :conditional_hello_with_bangs + assert_response :not_modified + end + protected def etag_for(text) %("#{Digest::MD5.hexdigest(text)}") end + + def expand_key(args) + ActiveSupport::Cache.expand_cache_key(args) + end end class LastModifiedRenderTest < Test::Unit::TestCase @@ -1402,6 +1429,18 @@ class LastModifiedRenderTest < Test::Unit::TestCase assert !@response.body.blank? assert_equal @last_modified, @response.headers['Last-Modified'] end + + def test_request_with_bang_gets_last_modified + get :conditional_hello_with_bangs + assert_equal @last_modified, @response.headers['Last-Modified'] + assert_response :success + end + + def test_request_with_bang_obeys_last_modified + @request.if_modified_since = @last_modified + get :conditional_hello_with_bangs + assert_response :not_modified + end end class RenderingLoggingTest < Test::Unit::TestCase diff --git a/actionpack/test/controller/rescue_test.rb b/actionpack/test/controller/rescue_test.rb index da076d2090..32c6c013f1 100644 --- a/actionpack/test/controller/rescue_test.rb +++ b/actionpack/test/controller/rescue_test.rb @@ -75,7 +75,7 @@ class RescueController < ActionController::Base def method_not_allowed raise ActionController::MethodNotAllowed.new(:get, :head, :put) end - + def not_implemented raise ActionController::NotImplemented.new(:get, :put) end @@ -107,7 +107,7 @@ class RescueController < ActionController::Base def record_invalid_raise_as_string raise RecordInvalidToRescueAsString end - + def bad_gateway raise BadGateway end @@ -135,18 +135,19 @@ class RescueController < ActionController::Base end end -class RescueTest < Test::Unit::TestCase +class RescueControllerTest < ActionController::TestCase FIXTURE_PUBLIC = "#{File.dirname(__FILE__)}/../fixtures".freeze - def setup - @controller = RescueController.new - @request = ActionController::TestRequest.new - @response = ActionController::TestResponse.new + setup :set_all_requests_local + setup :populate_exception_object + def set_all_requests_local RescueController.consider_all_requests_local = true @request.remote_addr = '1.2.3.4' @request.host = 'example.com' + end + def populate_exception_object begin raise 'foo' rescue => @exception @@ -307,7 +308,7 @@ class RescueTest < Test::Unit::TestCase assert_nil @controller.send(:clean_backtrace, Exception.new) end end - + def test_not_implemented with_all_requests_local false do with_rails_public_path(".") do @@ -463,14 +464,7 @@ class ExceptionInheritanceRescueController < ActionController::Base end end -class ExceptionInheritanceRescueTest < Test::Unit::TestCase - - def setup - @controller = ExceptionInheritanceRescueController.new - @request = ActionController::TestRequest.new - @response = ActionController::TestResponse.new - end - +class ExceptionInheritanceRescueControllerTest < ActionController::TestCase def test_bottom_first get :raise_grandchild_exception assert_response :no_content @@ -500,14 +494,7 @@ class ControllerInheritanceRescueController < ExceptionInheritanceRescueControll end end -class ControllerInheritanceRescueControllerTest < Test::Unit::TestCase - - def setup - @controller = ControllerInheritanceRescueController.new - @request = ActionController::TestRequest.new - @response = ActionController::TestResponse.new - end - +class ControllerInheritanceRescueControllerTest < ActionController::TestCase def test_first_exception_in_child_controller get :raise_first_exception_in_child_controller assert_response :gone diff --git a/actionpack/test/template/form_tag_helper_test.rb b/actionpack/test/template/form_tag_helper_test.rb index 6473d011d5..ad8baef5e4 100644 --- a/actionpack/test/template/form_tag_helper_test.rb +++ b/actionpack/test/template/form_tag_helper_test.rb @@ -271,6 +271,12 @@ class FormTagHelperTest < ActionView::TestCase expected = %(<fieldset>Hello world!</fieldset>) assert_dom_equal expected, output_buffer + + self.output_buffer = '' + field_set_tag('', :class => 'format') { concat "Hello world!" } + + expected = %(<fieldset class="format">Hello world!</fieldset>) + assert_dom_equal expected, output_buffer end def protect_against_forgery? |