Changeset 7178
- Timestamp:
- 07/11/07 02:39:31 (1 year ago)
- Files:
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
branches/1-2-stable/actionpack/CHANGELOG
r7161 r7178 1 1 *SVN* 2 3 * Fix errors with around_filters which do not yield, restore 1.1 behaviour with after filters. Closes #8891 [skaes] 4 5 After filters will *no longer* be run if an around_filter fails to yield, users relying on 6 this behaviour are advised to put the code in question after a yield statement in an around filter. 2 7 3 8 * Allow you to delete cookies with options. Closes #3685 [josh, Chris Wanstrath] branches/1-2-stable/actionpack/lib/action_controller/filters.rb
r6671 r7178 215 215 # 216 216 # <tt>before_filter</tt> and <tt>around_filter</tt> may halt the request 217 # before controller action is run. This is useful, for example, to deny217 # before a controller action is run. This is useful, for example, to deny 218 218 # access to unauthenticated users or to redirect from http to https. 219 219 # Simply return false from the filter or call render or redirect. 220 # After filters will not be executed if the filter chain is halted. 220 221 # 221 222 # Around filters halt the request unless the action block is called. … … 239 240 # . #around (code after yield) 240 241 # . / 241 # #after (actual filter code is run )242 # 243 # If #around returns before yielding, only #after willbe run. The #before244 # filter and controller action will not be run. If #before returns false,245 # the second half of #around and all of #after will still run butthe246 # action will not. 242 # #after (actual filter code is run, unless the around filter does not yield) 243 # 244 # If #around returns before yielding, #after will still not be run. The #before 245 # filter and controller action will not be run. If #before returns false, 246 # the second half of #around and will still run but #after and the 247 # action will not. If #around does not yield, #after will not be run. 247 248 module ClassMethods 248 249 # The passed <tt>filters</tt> will be appended to the filter_chain and … … 440 441 # only filters returning false are halted. 441 442 if false == @filter.call(controller) 442 controller. halt_filter_chain(@filter)443 controller.send :halt_filter_chain, @filter, :returned_false 443 444 end 444 445 end … … 529 530 def find_filter_append_position(filters, filter_type) 530 531 # appending an after filter puts it at the end of the call chain 531 # before and around filters go ebefore the first after filter in the chain532 # before and around filters go before the first after filter in the chain 532 533 unless filter_type == :after 533 534 filter_chain.each_with_index do |f,i| … … 656 657 Proc.new do |controller, action| 657 658 if filter.before(controller) == false 658 controller.send :halt_filter_chain, filter 659 controller.send :halt_filter_chain, filter, :returned_false 659 660 else 660 661 begin … … 677 678 end 678 679 679 def perform_action_with_filters 680 call_filters(self.class.filter_chain, 0, 0) 681 end 680 protected 682 681 683 682 def process_with_filters(request, response, method = :perform_action, *arguments) #:nodoc: … … 686 685 end 687 686 688 def filter_chain 689 self.class.filter_chain 687 def perform_action_with_filters 688 call_filters(self.class.filter_chain, 0, 0) 689 end 690 691 private 692 693 def call_filters(chain, index, nesting) 694 index = run_before_filters(chain, index, nesting) 695 aborted = @before_filter_chain_aborted 696 perform_action_without_filters unless performed? || aborted 697 return index if nesting != 0 || aborted 698 run_after_filters(chain, index) 690 699 end 691 700 … … 697 706 end 698 707 699 def call_filters(chain, index, nesting) 700 # run before filters until we find an after filter or around filter 708 def run_before_filters(chain, index, nesting) 701 709 while chain[index] 702 710 filter, index = skip_excluded_filters(chain, index) … … 704 712 case filter.type 705 713 when :before 706 # invoke before filter 707 filter.run(self) 714 filter.run(self) # invoke before filter 708 715 index = index.next 709 716 break if @before_filter_chain_aborted 710 717 when :around 718 yielded = false 711 719 filter.call(self) do 720 yielded = true 712 721 # all remaining before and around filters will be run in this call 713 722 index = call_filters(chain, index.next, nesting.next) 714 723 end 724 halt_filter_chain(filter, :did_not_yield) unless yielded 715 725 break 716 726 else 717 # no before or around filters left 718 break 719 end 720 end 721 722 aborted = @before_filter_chain_aborted 723 perform_action_without_filters unless performed? || aborted 724 return index if aborted || nesting != 0 725 726 # run after filters, if any 727 break # no before or around filters left 728 end 729 end 730 index 731 end 732 733 def run_after_filters(chain, index) 734 seen_after_filter = false 727 735 while chain[index] 728 736 filter, index = skip_excluded_filters(chain, index) 729 break unless filter 737 break unless filter # end of call chain reached 730 738 case filter.type 731 739 when :after 732 filter.run(self)733 index = index.next740 seen_after_filter = true 741 filter.run(self) # invoke after filter 734 742 else 735 raise ActionControllerError, "filter #{filter.inspect} was in the wrong place!" 736 end 737 end 738 743 # implementation error or someone has mucked with the filter chain 744 raise ActionControllerError, "filter #{filter.inspect} was in the wrong place!" if seen_after_filter 745 end 746 index = index.next 747 end 739 748 index.next 740 749 end 741 750 742 def halt_filter_chain(filter) 743 logger.info "Filter chain halted as [#{filter.inspect}] returned false." if logger 751 def halt_filter_chain(filter, reason) 744 752 @before_filter_chain_aborted = true 753 logger.info "Filter chain halted as [#{filter.inspect}] #{reason}." if logger 745 754 false 746 755 end 747 756 748 private 749 def process_cleanup_with_filters 750 if @before_filter_chain_aborted 751 close_session 752 else 753 process_cleanup_without_filters 754 end 755 end 757 def process_cleanup_with_filters 758 if @before_filter_chain_aborted 759 close_session 760 else 761 process_cleanup_without_filters 762 end 763 end 756 764 end 757 765 end branches/1-2-stable/actionpack/test/controller/filters_test.rb
r6671 r7178 324 324 render :text => 'hello' 325 325 end 326 end 327 328 class NonYieldingAroundFilterController < ActionController::Base 329 330 before_filter :filter_one 331 around_filter :non_yielding_filter 332 before_filter :filter_two 333 after_filter :filter_three 334 335 def index 336 render :inline => "index" 337 end 338 339 #make sure the controller complains 340 def rescue_action(e); raise e; end 341 342 private 343 344 def filter_one 345 @filters ||= [] 346 @filters << "filter_one" 347 end 348 349 def filter_two 350 @filters << "filter_two" 351 end 352 353 def non_yielding_filter 354 @filters << "zomg it didn't yield" 355 @filter_return_value 356 end 357 358 def filter_three 359 @filters << "filter_three" 360 end 361 362 end 363 364 def test_non_yielding_around_filters_not_returning_false_do_not_raise 365 controller = NonYieldingAroundFilterController.new 366 controller.instance_variable_set "@filter_return_value", true 367 assert_nothing_raised do 368 test_process(controller, "index") 369 end 370 end 371 372 def test_non_yielding_around_filters_returning_false_do_not_raise 373 controller = NonYieldingAroundFilterController.new 374 controller.instance_variable_set "@filter_return_value", false 375 assert_nothing_raised do 376 test_process(controller, "index") 377 end 378 end 379 380 def test_after_filters_are_not_run_if_around_filter_returns_false 381 controller = NonYieldingAroundFilterController.new 382 controller.instance_variable_set "@filter_return_value", false 383 test_process(controller, "index") 384 assert_equal ["filter_one", "zomg it didn't yield"], controller.assigns['filters'] 385 end 386 387 def test_after_filters_are_not_run_if_around_filter_does_not_yield 388 controller = NonYieldingAroundFilterController.new 389 controller.instance_variable_set "@filter_return_value", true 390 test_process(controller, "index") 391 assert_equal ["filter_one", "zomg it didn't yield"], controller.assigns['filters'] 326 392 end 327 393