Ruby on Rails | Screencasts | Download | Documentation | Weblog | Community | Source

Changeset 5268

Show
Ignore:
Timestamp:
10/09/06 06:11:40 (2 years ago)
Author:
bitsweat
Message:

r5540@ks: jeremy | 2006-10-08 23:05:30 -0700
#5949
r5541@ks: jeremy | 2006-10-08 23:07:08 -0700
Fix filter skipping in controller subclasses.
r5557@ks: jeremy | 2006-10-08 23:11:24 -0700
Update changelog. Closes #5949, references #6297, references #6299.

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • trunk/actionpack/CHANGELOG

    r5253 r5268  
    11*SVN* 
     2 
     3* Fix filter skipping in controller subclasses.  #5949, #6297, #6299 [Martin Emde] 
    24 
    35* render_text may optionally append to the response body. render_javascript appends by default. This allows you to chain multiple render :update calls by setting @performed_render = false between them (awaiting a better public API).  [Jeremy Kemper] 
  • trunk/actionpack/lib/action_controller/filters.rb

    r5196 r5268  
    363363      # Returns a mapping between filters and the actions that may run them. 
    364364      def included_actions #:nodoc: 
    365         filter_chain.inject({}) { |h,f| h[f.filter] = f.included_actions; h
     365        read_inheritable_attribute("included_actions") || {
    366366      end 
    367367 
    368368      # Returns a mapping between filters and actions that may not run them. 
    369369      def excluded_actions #:nodoc: 
    370         filter_chain.inject({}) { |h,f| h[f.filter] = f.excluded_actions; h
     370        read_inheritable_attribute("excluded_actions") || {
    371371      end 
    372372 
     
    378378      def find_filter(filter, &block) #:nodoc: 
    379379        filter_chain.select { |f| f.filter == filter && (!block_given? || yield(f)) }.first 
     380      end 
     381 
     382      # Returns true if the filter is excluded from the given action 
     383      def filter_excluded_from_action?(filter,action) #:nodoc: 
     384        if (ia = included_actions[filter]) && !ia.empty? 
     385          !ia.include?(action) 
     386        else 
     387          (excluded_actions[filter] || []).include?(action) 
     388        end 
    380389      end 
    381390 
     
    385394        attr_reader :filter, :included_actions, :excluded_actions 
    386395 
    387         def initialize(filter, options={}
     396        def initialize(filter
    388397          @filter = filter 
    389           @position = options[:position] 
    390           update_conditions(options) 
    391         end 
    392  
    393         def update_conditions(conditions) 
    394           if conditions[:only] 
    395             @included_actions = [conditions[:only]].flatten.map(&:to_s) 
    396           else 
    397             @excluded_actions = [conditions[:except]].flatten.compact.map(&:to_s) 
    398           end 
    399           build_excluded_actions_hash 
    400         end 
    401  
    402         def remove_actions_from_included_actions!(*actions) 
    403           if @included_actions 
    404             actions.flatten.map(&:to_s).each { |action| @included_actions.delete(action) } 
    405             build_excluded_actions_hash 
    406           end 
    407398        end 
    408399 
     
    415406        end 
    416407 
    417         def excluded_from?(action) 
    418           @excluded_actions_hash[action] 
    419         end 
    420  
    421408        def call(controller, &block) 
    422409          raise(ActionControllerError, 'No filter type: Nothing to do here.') 
    423         end 
    424  
    425         private 
    426         def build_excluded_actions_hash 
    427           @excluded_actions_hash = 
    428             if @included_actions 
    429               @included_actions.inject(Hash.new(true)){|h, a| h[a] = false; h} 
    430             else 
    431               @excluded_actions.inject(Hash.new(false)){|h, a| h[a] = true; h} 
    432             end 
    433410        end 
    434411      end 
     
    512489        def create_filters(filters, position, &block) #:nodoc: 
    513490          filters, conditions = extract_conditions(filters, &block) 
    514           conditions.merge!(:position => position) 
    515  
    516           # conditions should be blank for a filter behind a filter proxy since the proxy will take care of all conditions. 
    517           proxy_conditions, conditions = conditions, {} unless :around == position 
    518  
    519           filters.map do |filter| 
     491 
     492          filters.map! do |filter| 
    520493            # change all the filters into instances of Filter derived classes 
    521             class_for_filter(filter).new(filter, conditions) 
    522           end.collect do |filter| 
     494            class_for_filter(filter).new(filter) 
     495          end 
     496 
     497          filters.map! do |filter| 
    523498            # apply proxy to filter if necessary 
    524499            case position 
    525500            when :before 
    526               BeforeFilterProxy.new(filter, proxy_conditions
     501              BeforeFilterProxy.new(filter
    527502            when :after 
    528               AfterFilterProxy.new(filter, proxy_conditions
     503              AfterFilterProxy.new(filter
    529504            else 
    530505              filter 
    531506            end 
    532507          end 
     508 
     509          update_conditions(filters, conditions) 
     510 
     511          filters 
    533512        end 
    534513 
     
    554533        end 
    555534 
     535        def extract_conditions(*filters, &block) #:nodoc: 
     536          filters.flatten! 
     537          conditions = filters.last.is_a?(Hash) ? filters.pop : {} 
     538          filters << block if block_given? 
     539          return filters, conditions 
     540        end 
     541 
     542        def update_conditions(filters, conditions) 
     543          return if conditions.empty? 
     544          if conditions[:only] 
     545            write_inheritable_hash('included_actions', condition_hash(filters, conditions[:only])) 
     546          else 
     547            write_inheritable_hash('excluded_actions', condition_hash(filters, conditions[:except])) if conditions[:except] 
     548          end 
     549        end 
     550 
     551        def condition_hash(filters, *actions) 
     552          actions = actions.flatten.map(&:to_s) 
     553          filters.inject({}) { |h,f| h.update( f => (actions.blank? ? nil : actions)) } 
     554        end 
     555 
     556        def skip_filter_in_chain(*filters, &test) #:nodoc: 
     557          filters, conditions = extract_conditions(filters) 
     558          filters.map! { |f| block_given? ? find_filter(f, &test) : find_filter(f) } 
     559          filters.compact! 
     560 
     561          if conditions.empty? 
     562            delete_filters_in_chain(filters) 
     563          else 
     564            remove_actions_from_included_actions!(filters,conditions[:only] || []) 
     565            conditions[:only], conditions[:except] = conditions[:except], conditions[:only] 
     566            update_conditions(filters,conditions) 
     567          end 
     568        end 
     569 
     570        def remove_actions_from_included_actions!(filters,*actions) 
     571          actions = actions.flatten.map(&:to_s) 
     572          updated_hash = filters.inject(included_actions) do |hash,filter| 
     573            ia = (hash[filter] || []) - actions 
     574            ia.blank? ? hash.delete(filter) : hash[filter] = ia 
     575            hash 
     576          end 
     577          write_inheritable_attribute('included_actions', updated_hash) 
     578        end 
     579 
     580        def delete_filters_in_chain(filters) #:nodoc: 
     581          write_inheritable_attribute('filter_chain', filter_chain.reject { |f| filters.include?(f) }) 
     582        end 
     583 
    556584        def filter_responds_to_before_and_after(filter) #:nodoc: 
    557585          filter.respond_to?(:before) && filter.respond_to?(:after) 
     
    570598          end 
    571599        end 
    572  
    573         def extract_conditions(*filters, &block) #:nodoc: 
    574           filters.flatten! 
    575           conditions = filters.last.is_a?(Hash) ? filters.pop : {} 
    576           filters << block if block_given? 
    577           return filters.flatten, conditions 
    578         end 
    579  
    580         def skip_filter_in_chain(*filters, &test) #:nodoc: 
    581           filters, conditions = extract_conditions(filters) 
    582           finder_proc = block_given? ? 
    583             proc { |f| find_filter(f, &test) } : 
    584             proc { |f| find_filter(f) } 
    585  
    586           filters.map(&finder_proc).reject(&:nil?).each do |filter| 
    587             if conditions.empty? 
    588               delete_filter_in_chain(filter) 
    589             else 
    590               filter.remove_actions_from_included_actions!(conditions[:only] || []) 
    591               conditions[:only], conditions[:except] = conditions[:except], conditions[:only] 
    592               filter.update_conditions(conditions) 
    593             end 
    594           end 
    595         end 
    596  
    597         def delete_filter_in_chain(filter) #:nodoc: 
    598           write_inheritable_attribute('filter_chain', filter_chain.reject { |f| f == filter }) 
    599         end 
    600600    end 
    601601 
     
    628628        return (performed? || perform_action_without_filters) if index >= chain.size 
    629629        filter = chain[index] 
    630         return call_filter(chain, index.next) if filter.excluded_from?(action_name) 
     630        return call_filter(chain, index.next) if self.class.filter_excluded_from_action?(filter,action_name) 
    631631 
    632632        halted = false 
  • trunk/actionpack/test/controller/filters_test.rb

    r5196 r5268  
    155155      end 
    156156  end 
    157    
     157 
    158158  class ConditionalParentOfConditionalSkippingController < ConditionalFilterController 
    159159    before_filter :conditional_in_parent, :only => [:show, :another_action] 
     
    171171    skip_before_filter :conditional_in_parent, :only => :another_action 
    172172    skip_after_filter  :conditional_in_parent, :only => :another_action 
     173  end 
     174 
     175  class AnotherChildOfConditionalParentController < ConditionalParentOfConditionalSkippingController 
     176    skip_before_filter :conditional_in_parent, :only => :show 
    173177  end 
    174178 
     
    414418  end 
    415419 
     420  def test_condition_skipping_of_filters_when_siblings_also_have_conditions 
     421    assert_equal %w( conditional_in_parent conditional_in_parent ), test_process(ChildOfConditionalParentController).template.assigns['ran_filter'], "1" 
     422    assert_equal nil, test_process(AnotherChildOfConditionalParentController).template.assigns['ran_filter'] 
     423    assert_equal %w( conditional_in_parent conditional_in_parent ), test_process(ChildOfConditionalParentController).template.assigns['ran_filter'] 
     424  end 
     425 
    416426  private 
    417427    def test_process(controller, action = "show")