aboutsummaryrefslogtreecommitdiffstats
path: root/actionpack/lib/action_controller
diff options
context:
space:
mode:
authorMichael Koziarski <michael@koziarski.com>2007-07-11 02:29:25 +0000
committerMichael Koziarski <michael@koziarski.com>2007-07-11 02:29:25 +0000
commite80fabbbf46cadb69c30e6125ef0422f96ca8b6b (patch)
treefe063546b649f3cea09b35e24b8e76ca7d946f23 /actionpack/lib/action_controller
parentf7bd676c8d2fab1b22ede4e12242b37eb3336884 (diff)
downloadrails-e80fabbbf46cadb69c30e6125ef0422f96ca8b6b.tar.gz
rails-e80fabbbf46cadb69c30e6125ef0422f96ca8b6b.tar.bz2
rails-e80fabbbf46cadb69c30e6125ef0422f96ca8b6b.zip
Fix errors with around_filters which do not yield, restore 1.1 behaviour with after filters. Closes #8891 [skaes]
git-svn-id: http://svn-commit.rubyonrails.org/rails/trunk@7177 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
Diffstat (limited to 'actionpack/lib/action_controller')
-rw-r--r--actionpack/lib/action_controller/filters.rb94
1 files changed, 47 insertions, 47 deletions
diff --git a/actionpack/lib/action_controller/filters.rb b/actionpack/lib/action_controller/filters.rb
index 5705960eb5..c2f2c2a432 100644
--- a/actionpack/lib/action_controller/filters.rb
+++ b/actionpack/lib/action_controller/filters.rb
@@ -214,9 +214,10 @@ module ActionController #:nodoc:
# == Filter Chain Halting
#
# <tt>before_filter</tt> and <tt>around_filter</tt> may halt the request
- # before controller action is run. This is useful, for example, to deny
+ # before a controller action is run. This is useful, for example, to deny
# access to unauthenticated users or to redirect from http to https.
# Simply return false from the filter or call render or redirect.
+ # After filters will not be executed if the filter chain is halted.
#
# Around filters halt the request unless the action block is called.
# Given these filters
@@ -238,12 +239,12 @@ module ActionController #:nodoc:
# . . /
# . #around (code after yield)
# . /
- # #after (actual filter code is run)
+ # #after (actual filter code is run, unless the around filter does not yield)
#
- # If #around returns before yielding, only #after will be run. The #before
- # filter and controller action will not be run. If #before returns false,
- # the second half of #around and all of #after will still run but the
- # action will not.
+ # If #around returns before yielding, #after will still not be run. The #before
+ # filter and controller action will not be run. If #before returns false,
+ # the second half of #around and will still run but #after and the
+ # action will not. If #around fails to yield, #after will not be run.
module ClassMethods
# The passed <tt>filters</tt> will be appended to the filter_chain and
# will execute before the action on this controller is performed.
@@ -439,7 +440,7 @@ module ActionController #:nodoc:
def run(controller)
# only filters returning false are halted.
if false == @filter.call(controller)
- controller.halt_filter_chain(@filter)
+ controller.send :halt_filter_chain, @filter, :returned_false
end
end
@@ -528,7 +529,7 @@ module ActionController #:nodoc:
def find_filter_append_position(filters, filter_type)
# appending an after filter puts it at the end of the call chain
- # before and around filters goe before the first after filter in the chain
+ # before and around filters go before the first after filter in the chain
unless filter_type == :after
filter_chain.each_with_index do |f,i|
return i if f.after?
@@ -655,7 +656,7 @@ module ActionController #:nodoc:
return filter unless filter_responds_to_before_and_after(filter)
Proc.new do |controller, action|
if filter.before(controller) == false
- controller.send :halt_filter_chain, filter
+ controller.send :halt_filter_chain, filter, :returned_false
else
begin
action.call
@@ -675,8 +676,25 @@ module ActionController #:nodoc:
end
end
- def filter_chain
- self.class.filter_chain
+ protected
+
+ def process_with_filters(request, response, method = :perform_action, *arguments) #:nodoc:
+ @before_filter_chain_aborted = false
+ process_without_filters(request, response, method, *arguments)
+ end
+
+ def perform_action_with_filters
+ call_filters(self.class.filter_chain, 0, 0)
+ end
+
+ private
+
+ def call_filters(chain, index, nesting)
+ index = run_before_filters(chain, index, nesting)
+ aborted = @before_filter_chain_aborted
+ perform_action_without_filters unless performed? || aborted
+ return index if nesting != 0 || aborted
+ run_after_filters(chain, index)
end
def skip_excluded_filters(chain, index)
@@ -686,72 +704,54 @@ module ActionController #:nodoc:
[filter, index]
end
- def call_filters(chain, index, nesting)
- # run before filters until we find an after filter or around filter
+ def run_before_filters(chain, index, nesting)
while chain[index]
filter, index = skip_excluded_filters(chain, index)
break unless filter # end of call chain reached
case filter.type
when :before
- # invoke before filter
- filter.run(self)
+ filter.run(self) # invoke before filter
index = index.next
break if @before_filter_chain_aborted
when :around
+ yielded = false
filter.call(self) do
+ yielded = true
# all remaining before and around filters will be run in this call
index = call_filters(chain, index.next, nesting.next)
end
+ halt_filter_chain(filter, :did_not_yield) unless yielded
break
else
- # no before or around filters left
- break
+ break # no before or around filters left
end
end
+ index
+ end
- aborted = @before_filter_chain_aborted
- perform_action_without_filters unless performed? || aborted
- return index if aborted || nesting != 0
-
- # if an around filter catches an exception during rendering and handles it, e.g.
- # by rendering an error page, we might have left over around filters in the filter
- # chain. so skip over these.
- index = index.next while (filter = chain[index]) && filter.type == :around
-
- # run after filters, if any
+ def run_after_filters(chain, index)
+ seen_after_filter = false
while chain[index]
filter, index = skip_excluded_filters(chain, index)
- break unless filter
+ break unless filter # end of call chain reached
case filter.type
when :after
- filter.run(self)
- index = index.next
+ seen_after_filter = true
+ filter.run(self) # invoke after filter
else
- raise ActionControllerError, "filter #{filter.inspect} was in the wrong place!"
+ # implementation error or someone has mucked with the filter chain
+ raise ActionControllerError, "filter #{filter.inspect} was in the wrong place!" if seen_after_filter
end
+ index = index.next
end
-
index.next
end
- def halt_filter_chain(filter)
- logger.info "Filter chain halted as [#{filter.inspect}] returned false." if logger
+ def halt_filter_chain(filter, reason)
@before_filter_chain_aborted = true
+ logger.info "Filter chain halted as [#{filter.inspect}] #{reason}." if logger
false
end
-
- protected
-
- def process_with_filters(request, response, method = :perform_action, *arguments) #:nodoc:
- @before_filter_chain_aborted = false
- process_without_filters(request, response, method, *arguments)
- end
-
- private
- def perform_action_with_filters
- call_filters(self.class.filter_chain, 0, 0)
- end
-
end
end
end