Changeset 354
- Timestamp:
- 01/09/05 17:14:47 (4 years ago)
- Files:
-
- trunk/actionpack/CHANGELOG (modified) (1 diff)
- trunk/actionpack/lib/action_controller/filters.rb (modified) (10 diffs)
- trunk/actionpack/test/controller/filters_test.rb (modified) (2 diffs)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
trunk/actionpack/CHANGELOG
r352 r354 1 1 *SVN* 2 3 * Added conditional filters #431 [Marcel]. Example: 4 5 class JournalController < ActionController::Base 6 # only require authentication if the current action is edit or delete 7 before_filter :authorize, :only_on => [ :edit, :delete ] 8 9 private 10 def authorize 11 # redirect to login unless authenticated 12 end 13 end 2 14 3 15 * Added authentication framework to protect actions behind a condition and redirect on failure. See ActionController::Authentication for more. trunk/actionpack/lib/action_controller/filters.rb
r351 r354 127 127 # end 128 128 # end 129 # 130 # == Filter conditions 131 # 132 # Filters can be limited to run for only specific actions. This can be expressed either by listing the actions to 133 # exclude or the actions to include when executing the filter. Available conditions are +:only+ or +:except+, both 134 # of which accept an arbitrary number of method references. For example: 135 # 136 # class Journal < ActionController::Base 137 # # only require authentication if the current action is edit or delete 138 # before_filter :authorize, :only => [ :edit, :delete ] 139 # 140 # private 141 # def authorize 142 # # redirect to login unless authenticated 143 # end 144 # end 145 # 146 # When setting conditions on inline method (proc) filters the condition must come first and be placed in parenthesis. 147 # 148 # class UserPreferences < ActionController::Base 149 # before_filter(:except => :new) { # some proc ... } 150 # # ... 151 # end 152 # 129 153 module ClassMethods 130 154 # The passed <tt>filters</tt> will be appended to the array of filters that's run _before_ actions 131 155 # on this controller are performed. 132 156 def append_before_filter(*filters, &block) 157 conditions = extract_conditions!(filters) 133 158 filters << block if block_given? 159 add_action_conditions(filters, conditions) 134 160 append_filter_to_chain("before", filters) 135 161 end … … 138 164 # on this controller are performed. 139 165 def prepend_before_filter(*filters, &block) 166 conditions = extract_conditions!(filters) 140 167 filters << block if block_given? 168 add_action_conditions(filters, conditions) 141 169 prepend_filter_to_chain("before", filters) 142 170 end … … 148 176 # on this controller are performed. 149 177 def append_after_filter(*filters, &block) 178 conditions = extract_conditions!(filters) 150 179 filters << block if block_given? 180 add_action_conditions(filters, conditions) 151 181 append_filter_to_chain("after", filters) 152 182 end … … 155 185 # on this controller are performed. 156 186 def prepend_after_filter(*filters, &block) 187 conditions = extract_conditions!(filters) 157 188 filters << block if block_given? 189 add_action_conditions(filters, conditions) 158 190 prepend_filter_to_chain("after", filters) 159 191 end … … 170 202 # A#after 171 203 # B#after 172 def append_around_filter( filters)173 for filter in [filters].flatten204 def append_around_filter(*filters) 205 for filter in filters.flatten 174 206 ensure_filter_responds_to_before_and_after(filter) 175 207 append_before_filter { |c| filter.before(c) } … … 186 218 # B#after 187 219 # A#after 188 def prepend_around_filter( filters)189 for filter in [filters].flatten220 def prepend_around_filter(*filters) 221 for filter in filters.flatten 190 222 ensure_filter_responds_to_before_and_after(filter) 191 223 prepend_before_filter { |c| filter.before(c) } … … 205 237 def after_filters #:nodoc: 206 238 read_inheritable_attribute("after_filters") 239 end 240 241 # Returns a mapping between filters and the actions that may run them. 242 def included_actions #:nodoc: 243 read_inheritable_attribute("included_actions") || {} 244 end 245 246 # Returns a mapping between filters and actions that may not run them. 247 def excluded_actions #:nodoc: 248 read_inheritable_attribute("excluded_actions") || {} 207 249 end 208 250 … … 220 262 raise ActionControllerError, "Filter object must respond to both before and after" 221 263 end 264 end 265 266 def extract_conditions!(filters) 267 return nil unless filters.last.is_a? Hash 268 filters.pop 269 end 270 271 def add_action_conditions(filters, conditions) 272 return unless conditions 273 included, excluded = conditions[:only], conditions[:except] 274 write_inheritable_hash("included_actions", condition_hash(filters, included)) && return if included 275 write_inheritable_hash("excluded_actions", condition_hash(filters, excluded)) if excluded 276 end 277 278 def condition_hash(filters, *actions) 279 filters.inject({}) {|hash, filter| hash.merge(filter => actions.flatten.map {|action| action.to_s})} 222 280 end 223 281 end … … 253 311 def call_filters(filters) 254 312 filters.each do |filter| 255 if Symbol === filter 256 if self.send(filter) == false then return false end 257 elsif filter_block?(filter) 258 if filter.call(self) == false then return false end 259 elsif filter_class?(filter) 260 if filter.filter(self) == false then return false end 261 else 262 raise( 263 ActionControllerError, 264 "Filters need to be either a symbol, proc/method, or class implementing a static filter method" 265 ) 313 next if action_exempted?(filter) 314 filter_result = case 315 when filter.is_a?(Symbol) 316 self.send(filter) 317 when filter_block?(filter) 318 filter.call(self) 319 when filter_class?(filter) 320 filter.filter(self) 321 else 322 raise( 323 ActionControllerError, 324 "Filters need to be either a symbol, proc/method, or class implementing a static filter method" 325 ) 266 326 end 327 return false if filter_result == false 267 328 end 268 329 end … … 275 336 filter.respond_to?("filter") 276 337 end 338 339 def action_exempted?(filter) 340 case 341 when self.class.included_actions[filter] 342 !self.class.included_actions[filter].include?(action_name) 343 when self.class.excluded_actions[filter] 344 self.class.excluded_actions[filter].include?(action_name) 345 end 346 end 277 347 end 278 348 end trunk/actionpack/test/controller/filters_test.rb
r347 r354 16 16 end 17 17 18 class ConditionalFilterController < ActionController::Base 19 def show 20 render_text "ran action" 21 end 22 23 def another_action 24 render_text "ran action" 25 end 26 27 def show_without_filter 28 render_text "ran action without filter" 29 end 30 31 private 32 def ensure_login 33 @ran_filter ||= [] 34 @ran_filter << "ensure_login" 35 end 36 37 def clean_up_tmp 38 @ran_filter ||= [] 39 @ran_filter << "clean_up_tmp" 40 end 41 42 def rescue_action(e) raise(e) end 43 end 44 45 class ConditionalCollectionFilterController < ConditionalFilterController 46 before_filter :ensure_login, :except => [ :show_without_filter, :another_action ] 47 end 48 49 class OnlyConditionSymController < ConditionalFilterController 50 before_filter :ensure_login, :only => :show 51 end 52 53 class ExceptConditionSymController < ConditionalFilterController 54 before_filter :ensure_login, :except => :show_without_filter 55 end 56 57 class BeforeAndAfterConditionController < ConditionalFilterController 58 before_filter :ensure_login, :only => :show 59 after_filter :clean_up_tmp, :only => :show 60 end 61 62 class OnlyConditionProcController < ConditionalFilterController 63 before_filter(:only => :show) {|c| c.assigns["ran_proc_filter"] = true } 64 end 65 66 class ExceptConditionProcController < ConditionalFilterController 67 before_filter(:except => :show_without_filter) {|c| c.assigns["ran_proc_filter"] = true } 68 end 69 70 class ConditionalClassFilter 71 def self.filter(controller) controller.assigns["ran_class_filter"] = true end 72 end 73 74 class OnlyConditionClassController < ConditionalFilterController 75 before_filter ConditionalClassFilter, :only => :show 76 end 77 78 class ExceptConditionClassController < ConditionalFilterController 79 before_filter ConditionalClassFilter, :except => :show_without_filter 80 end 81 82 class AnomolousYetValidConditionController < ConditionalFilterController 83 before_filter(ConditionalClassFilter, :ensure_login, Proc.new {|c| c.assigns["ran_proc_filter1"] = true }, :except => :show_without_filter) { |c| c.assigns["ran_proc_filter2"] = true} 84 end 85 18 86 class PrependingController < TestController 19 87 prepend_before_filter :wonderful_life … … 127 195 end 128 196 197 def test_running_anomolous_yet_valid_condition_filters 198 response = test_process(AnomolousYetValidConditionController) 199 assert_equal %w( ensure_login ), response.template.assigns["ran_filter"] 200 assert response.template.assigns["ran_class_filter"] 201 assert response.template.assigns["ran_proc_filter1"] 202 assert response.template.assigns["ran_proc_filter2"] 203 204 response = test_process(AnomolousYetValidConditionController, "show_without_filter") 205 assert_equal nil, response.template.assigns["ran_filter"] 206 assert !response.template.assigns["ran_class_filter"] 207 assert !response.template.assigns["ran_proc_filter1"] 208 assert !response.template.assigns["ran_proc_filter2"] 209 end 210 211 def test_running_collection_condition_filters 212 assert_equal %w( ensure_login ), test_process(ConditionalCollectionFilterController).template.assigns["ran_filter"] 213 assert_equal nil, test_process(ConditionalCollectionFilterController, "show_without_filter").template.assigns["ran_filter"] 214 assert_equal nil, test_process(ConditionalCollectionFilterController, "another_action").template.assigns["ran_filter"] 215 end 216 217 def test_running_only_condition_filters 218 assert_equal %w( ensure_login ), test_process(OnlyConditionSymController).template.assigns["ran_filter"] 219 assert_equal nil, test_process(OnlyConditionSymController, "show_without_filter").template.assigns["ran_filter"] 220 221 assert test_process(OnlyConditionProcController).template.assigns["ran_proc_filter"] 222 assert !test_process(OnlyConditionProcController, "show_without_filter").template.assigns["ran_proc_filter"] 223 224 assert test_process(OnlyConditionClassController).template.assigns["ran_class_filter"] 225 assert !test_process(OnlyConditionClassController, "show_without_filter").template.assigns["ran_class_filter"] 226 end 227 228 def test_running_except_condition_filters 229 assert_equal %w( ensure_login ), test_process(ExceptConditionSymController).template.assigns["ran_filter"] 230 assert_equal nil, test_process(ExceptConditionSymController, "show_without_filter").template.assigns["ran_filter"] 231 232 assert test_process(ExceptConditionProcController).template.assigns["ran_proc_filter"] 233 assert !test_process(ExceptConditionProcController, "show_without_filter").template.assigns["ran_proc_filter"] 234 235 assert test_process(ExceptConditionClassController).template.assigns["ran_class_filter"] 236 assert !test_process(ExceptConditionClassController, "show_without_filter").template.assigns["ran_class_filter"] 237 end 238 239 def test_running_before_and_after_condition_filters 240 assert_equal %w( ensure_login clean_up_tmp), test_process(BeforeAndAfterConditionController).template.assigns["ran_filter"] 241 assert_equal nil, test_process(BeforeAndAfterConditionController, "show_without_filter").template.assigns["ran_filter"] 242 end 243 129 244 def test_bad_filter 130 245 assert_raises(ActionController::ActionControllerError) {