From 2ee84cc6f92d49ec7004d0c99d66c6feb05cee9c Mon Sep 17 00:00:00 2001 From: David Heinemeier Hansson Date: Thu, 20 Jan 2005 14:13:34 +0000 Subject: Fixed that all redirect and render calls now return true, so you can use the pattern of "do and return". Added that renders and redirects called in before_filters will have the same effect as returning false: stopping the chain. Added that only one render or redirect can happen per action. The first call wins and subsequent calls are ignored. git-svn-id: http://svn-commit.rubyonrails.org/rails/trunk@462 5ecf4fe2-1ee6-0310-87b1-e25e094e27de --- actionpack/CHANGELOG | 32 +++++++++++++++++++++++++++++ actionpack/lib/action_controller/base.rb | 21 ++++++++++++++++--- actionpack/lib/action_controller/filters.rb | 8 ++++---- actionpack/test/controller/filters_test.rb | 20 ++++++++++++++++++ 4 files changed, 74 insertions(+), 7 deletions(-) (limited to 'actionpack') diff --git a/actionpack/CHANGELOG b/actionpack/CHANGELOG index d8245a1d81..7438f5a4f0 100644 --- a/actionpack/CHANGELOG +++ b/actionpack/CHANGELOG @@ -1,3 +1,35 @@ +*SVN* + +* Fixed that a default fragment store wan't being set to MemoryStore as intended. + +* Fixed that all redirect and render calls now return true, so you can use the pattern of "do and return". Example: + + def show + redirect_to(:action => "login") and return unless @person.authenticated? + render_text "I won't happen unless the person is authenticated" + end + +* Added that renders and redirects called in before_filters will have the same effect as returning false: stopping the chain. Example: + + class WeblogController + before_filter { |c| c.send(:redirect_to_url("http://www.farfaraway.com")}) } + + def hello + render_text "I will never be called" + end + end + + +* Added that only one render or redirect can happen per action. The first call wins and subsequent calls are ignored. Example: + + def do_something + redirect_to :action => "elsewhere" + render_action "overthere" + end + + Only the redirect happens. The rendering call is simply ignored. + + *1.3.1* (January 18th, 2005) * Fixed a bug where cookies wouldn't be set if a symbol was used instead of a string as the key diff --git a/actionpack/lib/action_controller/base.rb b/actionpack/lib/action_controller/base.rb index 1662d59b81..37e3269aa8 100755 --- a/actionpack/lib/action_controller/base.rb +++ b/actionpack/lib/action_controller/base.rb @@ -163,6 +163,17 @@ module ActionController #:nodoc: # For more examples of redirecting options, have a look at the unit test in test/controller/url_test.rb. It's very readable and will give # you an excellent understanding of the different options and what they do. # + # == Calling multiple redirects or renders + # + # The rule for handling calls of multiple redirects and renders is that the first call wins. So in the following example: + # + # def do_something + # redirect_to :action => "elsewhere" + # render_action "overthere" + # end + # + # Only the redirect happens. The rendering call is simply ignored. + # # == Environments # # Action Controller works out of the box with CGI, FastCGI, and mod_ruby. CGI and mod_ruby controllers are triggered just the same using: @@ -385,11 +396,11 @@ module ActionController #:nodoc: # considerably faster than rendering through the template engine. # Use block for response body if provided (useful for deferred rendering or streaming output). def render_text(text = nil, status = nil, &block) #:doc: + return if performed? add_variables_to_assigns @response.headers["Status"] = status || DEFAULT_RENDER_STATUS_CODE @response.body = block_given? ? block : text @performed_render = true - return false end # Renders an empty response that can be used when the request is only interested in triggering an effect. Do note that good @@ -541,10 +552,10 @@ module ActionController #:nodoc: # redirect_to_url "http://www.rubyonrails.org". If the resource has moved permanently, it's possible to pass true as the # second parameter and the browser will get "301 Moved Permanently" instead of "302 Found". def redirect_to_url(url, permanently = false) #:doc: + return if performed? logger.info("Redirected to #{url}") unless logger.nil? @response.redirect(url, permanently) @performed_redirect = true - return false end # Resets the session by clearsing out all the objects stored within and initializing a new session object. @@ -594,13 +605,17 @@ module ActionController #:nodoc: def perform_action if action_methods.include?(action_name) || action_methods.include?('method_missing') send(action_name) - render unless @performed_render || @performed_redirect + render unless performed? elsif template_exists? && template_public? render else raise UnknownAction, "No action responded to #{action_name}", caller end end + + def performed? + @performed_render || @performed_redirect + end def action_methods action_controller_classes = self.class.ancestors.reject{ |a| [Object, Kernel].include?(a) } diff --git a/actionpack/lib/action_controller/filters.rb b/actionpack/lib/action_controller/filters.rb index 85df451501..1bf9bb2217 100644 --- a/actionpack/lib/action_controller/filters.rb +++ b/actionpack/lib/action_controller/filters.rb @@ -12,9 +12,9 @@ module ActionController #:nodoc: # # Filters have access to the request, response, and all the instance variables set by other filters in the chain # or by the action (in the case of after filters). Additionally, it's possible for a pre-processing before_filter - # to halt the processing before the intended action is processed by returning false. This is especially useful for - # filters like authentication where you're not interested in allowing the action to be performed if the proper - # credentials are not in order. + # to halt the processing before the intended action is processed by returning false or performing a redirect or render. + # This is especially useful for filters like authentication where you're not interested in allowing the action to be + # performed if the proper credentials are not in order. # # == Filter inheritance # @@ -290,7 +290,7 @@ module ActionController #:nodoc: end def perform_action_with_filters - return if before_action == false + return if before_action == false || performed? perform_action_without_filters after_action end diff --git a/actionpack/test/controller/filters_test.rb b/actionpack/test/controller/filters_test.rb index 58490aebba..2cc51f1e25 100644 --- a/actionpack/test/controller/filters_test.rb +++ b/actionpack/test/controller/filters_test.rb @@ -14,6 +14,20 @@ class FilterTest < Test::Unit::TestCase @ran_filter << "ensure_login" end end + + class RenderingController < ActionController::Base + before_filter :render_something_else + + def show + @ran_action = true + render_text "ran action" + end + + private + def render_something_else + render_text "something else" + end + end class ConditionalFilterController < ActionController::Base def show @@ -264,6 +278,12 @@ class FilterTest < Test::Unit::TestCase " after appended aroundfilter after aroundfilter after procfilter ", MixedFilterController.execution_log end + + def test_rendering_breaks_filtering_chain + response = test_process(RenderingController) + assert_equal "something else", response.body + assert !response.template.assigns["ran_action"] + end private def test_process(controller, action = "show") -- cgit v1.2.3