actionpack 2.0.5 → 2.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/CHANGELOG +149 -7
- data/MIT-LICENSE +1 -1
- data/README +1 -1
- data/Rakefile +5 -6
- data/lib/action_controller.rb +2 -2
- data/lib/action_controller/assertions/model_assertions.rb +2 -1
- data/lib/action_controller/assertions/response_assertions.rb +4 -2
- data/lib/action_controller/assertions/routing_assertions.rb +3 -3
- data/lib/action_controller/assertions/selector_assertions.rb +30 -27
- data/lib/action_controller/assertions/tag_assertions.rb +3 -3
- data/lib/action_controller/base.rb +103 -129
- data/lib/action_controller/benchmarking.rb +3 -3
- data/lib/action_controller/caching.rb +41 -652
- data/lib/action_controller/caching/actions.rb +144 -0
- data/lib/action_controller/caching/fragments.rb +138 -0
- data/lib/action_controller/caching/pages.rb +154 -0
- data/lib/action_controller/caching/sql_cache.rb +18 -0
- data/lib/action_controller/caching/sweeping.rb +97 -0
- data/lib/action_controller/cgi_ext/cookie.rb +27 -23
- data/lib/action_controller/cgi_ext/stdinput.rb +1 -0
- data/lib/action_controller/cgi_process.rb +6 -4
- data/lib/action_controller/components.rb +7 -6
- data/lib/action_controller/cookies.rb +31 -19
- data/lib/action_controller/dispatcher.rb +51 -84
- data/lib/action_controller/filters.rb +295 -421
- data/lib/action_controller/flash.rb +1 -6
- data/lib/action_controller/headers.rb +31 -0
- data/lib/action_controller/helpers.rb +26 -9
- data/lib/action_controller/http_authentication.rb +1 -1
- data/lib/action_controller/integration.rb +65 -13
- data/lib/action_controller/layout.rb +24 -39
- data/lib/action_controller/mime_responds.rb +7 -3
- data/lib/action_controller/mime_type.rb +25 -9
- data/lib/action_controller/mime_types.rb +1 -1
- data/lib/action_controller/polymorphic_routes.rb +32 -17
- data/lib/action_controller/record_identifier.rb +10 -4
- data/lib/action_controller/request.rb +46 -30
- data/lib/action_controller/request_forgery_protection.rb +10 -9
- data/lib/action_controller/request_profiler.rb +29 -8
- data/lib/action_controller/rescue.rb +24 -24
- data/lib/action_controller/resources.rb +66 -23
- data/lib/action_controller/response.rb +2 -2
- data/lib/action_controller/routing.rb +113 -1229
- data/lib/action_controller/routing/builder.rb +204 -0
- data/lib/action_controller/{routing_optimisation.rb → routing/optimisations.rb} +13 -12
- data/lib/action_controller/routing/recognition_optimisation.rb +158 -0
- data/lib/action_controller/routing/route.rb +240 -0
- data/lib/action_controller/routing/route_set.rb +435 -0
- data/lib/action_controller/routing/routing_ext.rb +46 -0
- data/lib/action_controller/routing/segments.rb +283 -0
- data/lib/action_controller/session/active_record_store.rb +13 -8
- data/lib/action_controller/session/cookie_store.rb +20 -17
- data/lib/action_controller/session_management.rb +10 -3
- data/lib/action_controller/streaming.rb +45 -31
- data/lib/action_controller/test_case.rb +33 -23
- data/lib/action_controller/test_process.rb +39 -35
- data/lib/action_controller/url_rewriter.rb +18 -12
- data/lib/action_controller/vendor/html-scanner/html/tokenizer.rb +1 -1
- data/lib/action_pack.rb +1 -1
- data/lib/action_pack/version.rb +2 -2
- data/lib/action_view.rb +11 -3
- data/lib/action_view/base.rb +73 -390
- data/lib/action_view/helpers/active_record_helper.rb +83 -62
- data/lib/action_view/helpers/asset_tag_helper.rb +101 -44
- data/lib/action_view/helpers/atom_feed_helper.rb +35 -7
- data/lib/action_view/helpers/benchmark_helper.rb +5 -3
- data/lib/action_view/helpers/cache_helper.rb +3 -2
- data/lib/action_view/helpers/capture_helper.rb +1 -2
- data/lib/action_view/helpers/date_helper.rb +104 -82
- data/lib/action_view/helpers/form_helper.rb +148 -75
- data/lib/action_view/helpers/form_options_helper.rb +44 -23
- data/lib/action_view/helpers/form_tag_helper.rb +22 -13
- data/lib/action_view/helpers/javascripts/controls.js +1 -1
- data/lib/action_view/helpers/javascripts/dragdrop.js +1 -1
- data/lib/action_view/helpers/javascripts/effects.js +1 -1
- data/lib/action_view/helpers/number_helper.rb +10 -3
- data/lib/action_view/helpers/prototype_helper.rb +61 -29
- data/lib/action_view/helpers/record_tag_helper.rb +3 -3
- data/lib/action_view/helpers/sanitize_helper.rb +23 -17
- data/lib/action_view/helpers/scriptaculous_helper.rb +86 -60
- data/lib/action_view/helpers/text_helper.rb +153 -125
- data/lib/action_view/helpers/url_helper.rb +83 -28
- data/lib/action_view/inline_template.rb +20 -0
- data/lib/action_view/partial_template.rb +70 -0
- data/lib/action_view/partials.rb +31 -73
- data/lib/action_view/template.rb +127 -0
- data/lib/action_view/template_error.rb +8 -7
- data/lib/action_view/template_finder.rb +177 -0
- data/lib/action_view/template_handler.rb +18 -1
- data/lib/action_view/template_handlers/builder.rb +10 -2
- data/lib/action_view/template_handlers/compilable.rb +128 -0
- data/lib/action_view/template_handlers/erb.rb +37 -2
- data/lib/action_view/template_handlers/rjs.rb +14 -1
- data/lib/action_view/test_case.rb +58 -0
- data/test/abstract_unit.rb +1 -1
- data/test/active_record_unit.rb +3 -6
- data/test/activerecord/active_record_store_test.rb +1 -2
- data/test/activerecord/render_partial_with_record_identification_test.rb +158 -41
- data/test/adv_attr_test.rb +20 -0
- data/test/controller/action_pack_assertions_test.rb +16 -19
- data/test/controller/addresses_render_test.rb +1 -1
- data/test/controller/assert_select_test.rb +13 -6
- data/test/controller/base_test.rb +48 -2
- data/test/controller/benchmark_test.rb +1 -2
- data/test/controller/caching_test.rb +282 -21
- data/test/controller/capture_test.rb +1 -1
- data/test/controller/cgi_test.rb +1 -1
- data/test/controller/components_test.rb +1 -1
- data/test/controller/content_type_test.rb +2 -2
- data/test/controller/cookie_test.rb +13 -2
- data/test/controller/custom_handler_test.rb +14 -10
- data/test/controller/deprecation/deprecated_base_methods_test.rb +1 -1
- data/test/controller/dispatcher_test.rb +31 -49
- data/test/controller/fake_controllers.rb +17 -0
- data/test/controller/fake_models.rb +6 -0
- data/test/controller/filter_params_test.rb +14 -8
- data/test/controller/filters_test.rb +44 -16
- data/test/controller/flash_test.rb +2 -2
- data/test/controller/header_test.rb +14 -0
- data/test/controller/helper_test.rb +19 -15
- data/test/controller/html-scanner/document_test.rb +1 -2
- data/test/controller/html-scanner/node_test.rb +1 -2
- data/test/controller/html-scanner/sanitizer_test.rb +8 -5
- data/test/controller/html-scanner/tag_node_test.rb +1 -2
- data/test/controller/html-scanner/text_node_test.rb +2 -3
- data/test/controller/html-scanner/tokenizer_test.rb +8 -2
- data/test/controller/http_authentication_test.rb +1 -1
- data/test/controller/integration_test.rb +14 -16
- data/test/controller/integration_upload_test.rb +43 -0
- data/test/controller/layout_test.rb +26 -6
- data/test/controller/mime_responds_test.rb +39 -7
- data/test/controller/mime_type_test.rb +29 -5
- data/test/controller/new_render_test.rb +105 -34
- data/test/controller/polymorphic_routes_test.rb +32 -20
- data/test/controller/record_identifier_test.rb +38 -2
- data/test/controller/redirect_test.rb +21 -1
- data/test/controller/render_test.rb +59 -15
- data/test/controller/request_forgery_protection_test.rb +92 -5
- data/test/controller/request_test.rb +64 -6
- data/test/controller/rescue_test.rb +22 -6
- data/test/controller/resources_test.rb +102 -14
- data/test/controller/routing_test.rb +231 -19
- data/test/controller/selector_test.rb +2 -2
- data/test/controller/send_file_test.rb +14 -3
- data/test/controller/session/cookie_store_test.rb +16 -4
- data/test/controller/session/mem_cache_store_test.rb +3 -4
- data/test/controller/session_fixation_test.rb +1 -1
- data/test/controller/session_management_test.rb +23 -1
- data/test/controller/test_test.rb +39 -18
- data/test/controller/url_rewriter_test.rb +35 -1
- data/test/controller/verification_test.rb +1 -1
- data/test/controller/view_paths_test.rb +15 -12
- data/test/controller/webservice_test.rb +48 -3
- data/test/fixtures/bad_customers/_bad_customer.html.erb +1 -0
- data/test/fixtures/company.rb +1 -0
- data/test/fixtures/customers/_customer.html.erb +1 -0
- data/test/fixtures/db_definitions/sqlite.sql +6 -0
- data/test/fixtures/functional_caching/_partial.erb +3 -0
- data/test/fixtures/functional_caching/fragment_cached.html.erb +2 -0
- data/test/fixtures/functional_caching/html_fragment_cached_with_partial.html.erb +1 -0
- data/test/fixtures/functional_caching/js_fragment_cached_with_partial.js.rjs +1 -0
- data/test/fixtures/good_customers/_good_customer.html.erb +1 -0
- data/test/fixtures/mascot.rb +3 -0
- data/test/fixtures/mascots.yml +4 -0
- data/test/fixtures/mascots/_mascot.html.erb +1 -0
- data/test/fixtures/multipart/boundary_problem_file +10 -0
- data/test/fixtures/public/javascripts/application.js +1 -0
- data/test/fixtures/public/javascripts/controls.js +1 -0
- data/test/fixtures/public/javascripts/dragdrop.js +1 -0
- data/test/fixtures/public/javascripts/effects.js +1 -0
- data/test/fixtures/public/javascripts/prototype.js +1 -0
- data/test/fixtures/public/javascripts/version.1.0.js +1 -0
- data/test/fixtures/public/stylesheets/version.1.0.css +1 -0
- data/test/fixtures/reply.rb +1 -0
- data/test/fixtures/shared.html.erb +1 -0
- data/test/fixtures/symlink_parent/symlinked_layout.erb +5 -0
- data/test/fixtures/test/_customer_counter.erb +1 -0
- data/test/fixtures/test/_form.erb +1 -0
- data/test/fixtures/test/_labelling_form.erb +1 -0
- data/test/fixtures/test/_raise.html.erb +1 -0
- data/test/fixtures/test/greeting.js.rjs +1 -0
- data/test/fixtures/topics/_topic.html.erb +1 -0
- data/test/template/active_record_helper_test.rb +25 -8
- data/test/template/asset_tag_helper_test.rb +100 -17
- data/test/template/atom_feed_helper_test.rb +29 -1
- data/test/template/benchmark_helper_test.rb +10 -22
- data/test/template/date_helper_test.rb +455 -153
- data/test/template/erb_util_test.rb +10 -42
- data/test/template/form_helper_test.rb +192 -66
- data/test/template/form_options_helper_test.rb +19 -8
- data/test/template/form_tag_helper_test.rb +11 -8
- data/test/template/javascript_helper_test.rb +3 -9
- data/test/template/number_helper_test.rb +6 -3
- data/test/template/prototype_helper_test.rb +27 -40
- data/test/template/record_tag_helper_test.rb +54 -0
- data/test/template/sanitize_helper_test.rb +5 -6
- data/test/template/scriptaculous_helper_test.rb +7 -13
- data/test/template/tag_helper_test.rb +3 -6
- data/test/template/template_finder_test.rb +73 -0
- data/test/template/template_object_test.rb +95 -0
- data/test/template/test_test.rb +56 -0
- data/test/template/text_helper_test.rb +46 -33
- data/test/template/url_helper_test.rb +8 -10
- metadata +65 -12
- data/lib/action_view/compiled_templates.rb +0 -69
- data/test/action_view_test.rb +0 -44
- data/test/activerecord/fixtures_test.rb +0 -24
- data/test/controller/fragment_store_setting_test.rb +0 -47
- data/test/template/compiled_templates_test.rb +0 -197
- data/test/template/deprecate_ivars_test.rb +0 -51
|
@@ -100,10 +100,10 @@ module ActionController #:nodoc:
|
|
|
100
100
|
#
|
|
101
101
|
# Around filters wrap an action, executing code both before and after.
|
|
102
102
|
# They may be declared as method references, blocks, or objects responding
|
|
103
|
-
# to
|
|
103
|
+
# to +filter+ or to both +before+ and +after+.
|
|
104
104
|
#
|
|
105
|
-
# To use a method as an around_filter
|
|
106
|
-
# Yield (or block.call) within the method to run the action.
|
|
105
|
+
# To use a method as an +around_filter+, pass a symbol naming the Ruby method.
|
|
106
|
+
# Yield (or <tt>block.call</tt>) within the method to run the action.
|
|
107
107
|
#
|
|
108
108
|
# around_filter :catch_exceptions
|
|
109
109
|
#
|
|
@@ -115,9 +115,9 @@ module ActionController #:nodoc:
|
|
|
115
115
|
# raise
|
|
116
116
|
# end
|
|
117
117
|
#
|
|
118
|
-
# To use a block as an around_filter
|
|
118
|
+
# To use a block as an +around_filter+, pass a block taking as args both
|
|
119
119
|
# the controller and the action block. You can't call yield directly from
|
|
120
|
-
# an around_filter block; explicitly call the action block instead:
|
|
120
|
+
# an +around_filter+ block; explicitly call the action block instead:
|
|
121
121
|
#
|
|
122
122
|
# around_filter do |controller, action|
|
|
123
123
|
# logger.debug "before #{controller.action_name}"
|
|
@@ -125,9 +125,9 @@ module ActionController #:nodoc:
|
|
|
125
125
|
# logger.debug "after #{controller.action_name}"
|
|
126
126
|
# end
|
|
127
127
|
#
|
|
128
|
-
# To use a filter object with around_filter
|
|
129
|
-
# to
|
|
130
|
-
# the block as above:
|
|
128
|
+
# To use a filter object with +around_filter+, pass an object responding
|
|
129
|
+
# to <tt>:filter</tt> or both <tt>:before</tt> and <tt>:after</tt>. With a
|
|
130
|
+
# filter method, yield to the block as above:
|
|
131
131
|
#
|
|
132
132
|
# around_filter BenchmarkingFilter
|
|
133
133
|
#
|
|
@@ -137,7 +137,7 @@ module ActionController #:nodoc:
|
|
|
137
137
|
# end
|
|
138
138
|
# end
|
|
139
139
|
#
|
|
140
|
-
# With before and after methods:
|
|
140
|
+
# With +before+ and +after+ methods:
|
|
141
141
|
#
|
|
142
142
|
# around_filter Authorizer.new
|
|
143
143
|
#
|
|
@@ -154,9 +154,9 @@ module ActionController #:nodoc:
|
|
|
154
154
|
# end
|
|
155
155
|
# end
|
|
156
156
|
#
|
|
157
|
-
# If the filter has before and after methods, the before method will be
|
|
158
|
-
# called before the action. If before renders or redirects, the filter chain is
|
|
159
|
-
# halted and after will not be run. See Filter Chain Halting below for
|
|
157
|
+
# If the filter has +before+ and +after+ methods, the +before+ method will be
|
|
158
|
+
# called before the action. If +before+ renders or redirects, the filter chain is
|
|
159
|
+
# halted and +after+ will not be run. See Filter Chain Halting below for
|
|
160
160
|
# an example.
|
|
161
161
|
#
|
|
162
162
|
# == Filter chain skipping
|
|
@@ -191,8 +191,9 @@ module ActionController #:nodoc:
|
|
|
191
191
|
# == Filter conditions
|
|
192
192
|
#
|
|
193
193
|
# Filters may be limited to specific actions by declaring the actions to
|
|
194
|
-
# include or exclude. Both options accept single actions
|
|
195
|
-
# or arrays of actions
|
|
194
|
+
# include or exclude. Both options accept single actions
|
|
195
|
+
# (<tt>:only => :index</tt>) or arrays of actions
|
|
196
|
+
# (<tt>:except => [:foo, :bar]</tt>).
|
|
196
197
|
#
|
|
197
198
|
# class Journal < ActionController::Base
|
|
198
199
|
# # Require authentication for edit and delete.
|
|
@@ -214,7 +215,7 @@ module ActionController #:nodoc:
|
|
|
214
215
|
#
|
|
215
216
|
# <tt>before_filter</tt> and <tt>around_filter</tt> may halt the request
|
|
216
217
|
# before a controller action is run. This is useful, for example, to deny
|
|
217
|
-
# access to unauthenticated users or to redirect from
|
|
218
|
+
# access to unauthenticated users or to redirect from HTTP to HTTPS.
|
|
218
219
|
# Simply call render or redirect. After filters will not be executed if the filter
|
|
219
220
|
# chain is halted.
|
|
220
221
|
#
|
|
@@ -240,21 +241,216 @@ module ActionController #:nodoc:
|
|
|
240
241
|
# . /
|
|
241
242
|
# #after (actual filter code is run, unless the around filter does not yield)
|
|
242
243
|
#
|
|
243
|
-
# If
|
|
244
|
-
# filter and controller action will not be run. If
|
|
245
|
-
# the second half of
|
|
246
|
-
# action will not. If
|
|
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+ renders or redirects,
|
|
246
|
+
# the second half of +around+ and will still run but +after+ and the
|
|
247
|
+
# action will not. If +around+ fails to yield, +after+ will not be run.
|
|
248
|
+
|
|
249
|
+
class FilterChain < ActiveSupport::Callbacks::CallbackChain #:nodoc:
|
|
250
|
+
def append_filter_to_chain(filters, filter_type, &block)
|
|
251
|
+
pos = find_filter_append_position(filters, filter_type)
|
|
252
|
+
update_filter_chain(filters, filter_type, pos, &block)
|
|
253
|
+
end
|
|
254
|
+
|
|
255
|
+
def prepend_filter_to_chain(filters, filter_type, &block)
|
|
256
|
+
pos = find_filter_prepend_position(filters, filter_type)
|
|
257
|
+
update_filter_chain(filters, filter_type, pos, &block)
|
|
258
|
+
end
|
|
259
|
+
|
|
260
|
+
def create_filters(filters, filter_type, &block)
|
|
261
|
+
filters, conditions = extract_options(filters, &block)
|
|
262
|
+
filters.map! { |filter| find_or_create_filter(filter, filter_type, conditions) }
|
|
263
|
+
filters
|
|
264
|
+
end
|
|
265
|
+
|
|
266
|
+
def skip_filter_in_chain(*filters, &test)
|
|
267
|
+
filters, conditions = extract_options(filters)
|
|
268
|
+
filters.each do |filter|
|
|
269
|
+
if callback = find(filter) then delete(callback) end
|
|
270
|
+
end if conditions.empty?
|
|
271
|
+
update_filter_in_chain(filters, :skip => conditions, &test)
|
|
272
|
+
end
|
|
273
|
+
|
|
274
|
+
private
|
|
275
|
+
def update_filter_chain(filters, filter_type, pos, &block)
|
|
276
|
+
new_filters = create_filters(filters, filter_type, &block)
|
|
277
|
+
insert(pos, new_filters).flatten!
|
|
278
|
+
end
|
|
279
|
+
|
|
280
|
+
def find_filter_append_position(filters, filter_type)
|
|
281
|
+
# appending an after filter puts it at the end of the call chain
|
|
282
|
+
# before and around filters go before the first after filter in the chain
|
|
283
|
+
unless filter_type == :after
|
|
284
|
+
each_with_index do |f,i|
|
|
285
|
+
return i if f.after?
|
|
286
|
+
end
|
|
287
|
+
end
|
|
288
|
+
return -1
|
|
289
|
+
end
|
|
290
|
+
|
|
291
|
+
def find_filter_prepend_position(filters, filter_type)
|
|
292
|
+
# prepending a before or around filter puts it at the front of the call chain
|
|
293
|
+
# after filters go before the first after filter in the chain
|
|
294
|
+
if filter_type == :after
|
|
295
|
+
each_with_index do |f,i|
|
|
296
|
+
return i if f.after?
|
|
297
|
+
end
|
|
298
|
+
return -1
|
|
299
|
+
end
|
|
300
|
+
return 0
|
|
301
|
+
end
|
|
302
|
+
|
|
303
|
+
def find_or_create_filter(filter, filter_type, options = {})
|
|
304
|
+
update_filter_in_chain([filter], options)
|
|
305
|
+
|
|
306
|
+
if found_filter = find(filter) { |f| f.type == filter_type }
|
|
307
|
+
found_filter
|
|
308
|
+
else
|
|
309
|
+
filter_kind = case
|
|
310
|
+
when filter.respond_to?(:before) && filter_type == :before
|
|
311
|
+
:before
|
|
312
|
+
when filter.respond_to?(:after) && filter_type == :after
|
|
313
|
+
:after
|
|
314
|
+
else
|
|
315
|
+
:filter
|
|
316
|
+
end
|
|
317
|
+
|
|
318
|
+
case filter_type
|
|
319
|
+
when :before
|
|
320
|
+
BeforeFilter.new(filter_kind, filter, options)
|
|
321
|
+
when :after
|
|
322
|
+
AfterFilter.new(filter_kind, filter, options)
|
|
323
|
+
else
|
|
324
|
+
AroundFilter.new(filter_kind, filter, options)
|
|
325
|
+
end
|
|
326
|
+
end
|
|
327
|
+
end
|
|
328
|
+
|
|
329
|
+
def update_filter_in_chain(filters, options, &test)
|
|
330
|
+
filters.map! { |f| block_given? ? find(f, &test) : find(f) }
|
|
331
|
+
filters.compact!
|
|
332
|
+
|
|
333
|
+
map! do |filter|
|
|
334
|
+
if filters.include?(filter)
|
|
335
|
+
new_filter = filter.dup
|
|
336
|
+
new_filter.options.merge!(options)
|
|
337
|
+
new_filter
|
|
338
|
+
else
|
|
339
|
+
filter
|
|
340
|
+
end
|
|
341
|
+
end
|
|
342
|
+
end
|
|
343
|
+
end
|
|
344
|
+
|
|
345
|
+
class Filter < ActiveSupport::Callbacks::Callback #:nodoc:
|
|
346
|
+
def before?
|
|
347
|
+
self.class == BeforeFilter
|
|
348
|
+
end
|
|
349
|
+
|
|
350
|
+
def after?
|
|
351
|
+
self.class == AfterFilter
|
|
352
|
+
end
|
|
353
|
+
|
|
354
|
+
def around?
|
|
355
|
+
self.class == AroundFilter
|
|
356
|
+
end
|
|
357
|
+
|
|
358
|
+
private
|
|
359
|
+
def should_not_skip?(controller)
|
|
360
|
+
if options[:skip]
|
|
361
|
+
!included_in_action?(controller, options[:skip])
|
|
362
|
+
else
|
|
363
|
+
true
|
|
364
|
+
end
|
|
365
|
+
end
|
|
366
|
+
|
|
367
|
+
def included_in_action?(controller, options)
|
|
368
|
+
if options[:only]
|
|
369
|
+
Array(options[:only]).map(&:to_s).include?(controller.action_name)
|
|
370
|
+
elsif options[:except]
|
|
371
|
+
!Array(options[:except]).map(&:to_s).include?(controller.action_name)
|
|
372
|
+
else
|
|
373
|
+
true
|
|
374
|
+
end
|
|
375
|
+
end
|
|
376
|
+
|
|
377
|
+
def should_run_callback?(controller)
|
|
378
|
+
should_not_skip?(controller) && included_in_action?(controller, options) && super
|
|
379
|
+
end
|
|
380
|
+
end
|
|
381
|
+
|
|
382
|
+
class AroundFilter < Filter #:nodoc:
|
|
383
|
+
def type
|
|
384
|
+
:around
|
|
385
|
+
end
|
|
386
|
+
|
|
387
|
+
def call(controller, &block)
|
|
388
|
+
if should_run_callback?(controller)
|
|
389
|
+
method = filter_responds_to_before_and_after? ? around_proc : self.method
|
|
390
|
+
|
|
391
|
+
# For around_filter do |controller, action|
|
|
392
|
+
if method.is_a?(Proc) && method.arity == 2
|
|
393
|
+
evaluate_method(method, controller, block)
|
|
394
|
+
else
|
|
395
|
+
evaluate_method(method, controller, &block)
|
|
396
|
+
end
|
|
397
|
+
else
|
|
398
|
+
block.call
|
|
399
|
+
end
|
|
400
|
+
end
|
|
401
|
+
|
|
402
|
+
private
|
|
403
|
+
def filter_responds_to_before_and_after?
|
|
404
|
+
method.respond_to?(:before) && method.respond_to?(:after)
|
|
405
|
+
end
|
|
406
|
+
|
|
407
|
+
def around_proc
|
|
408
|
+
Proc.new do |controller, action|
|
|
409
|
+
method.before(controller)
|
|
410
|
+
|
|
411
|
+
if controller.send!(:performed?)
|
|
412
|
+
controller.send!(:halt_filter_chain, method, :rendered_or_redirected)
|
|
413
|
+
else
|
|
414
|
+
begin
|
|
415
|
+
action.call
|
|
416
|
+
ensure
|
|
417
|
+
method.after(controller)
|
|
418
|
+
end
|
|
419
|
+
end
|
|
420
|
+
end
|
|
421
|
+
end
|
|
422
|
+
end
|
|
423
|
+
|
|
424
|
+
class BeforeFilter < Filter #:nodoc:
|
|
425
|
+
def type
|
|
426
|
+
:before
|
|
427
|
+
end
|
|
428
|
+
|
|
429
|
+
def call(controller, &block)
|
|
430
|
+
super
|
|
431
|
+
if controller.send!(:performed?)
|
|
432
|
+
controller.send!(:halt_filter_chain, method, :rendered_or_redirected)
|
|
433
|
+
end
|
|
434
|
+
end
|
|
435
|
+
end
|
|
436
|
+
|
|
437
|
+
class AfterFilter < Filter #:nodoc:
|
|
438
|
+
def type
|
|
439
|
+
:after
|
|
440
|
+
end
|
|
441
|
+
end
|
|
442
|
+
|
|
247
443
|
module ClassMethods
|
|
248
444
|
# The passed <tt>filters</tt> will be appended to the filter_chain and
|
|
249
445
|
# will execute before the action on this controller is performed.
|
|
250
446
|
def append_before_filter(*filters, &block)
|
|
251
|
-
append_filter_to_chain(filters, :before, &block)
|
|
447
|
+
filter_chain.append_filter_to_chain(filters, :before, &block)
|
|
252
448
|
end
|
|
253
449
|
|
|
254
450
|
# The passed <tt>filters</tt> will be prepended to the filter_chain and
|
|
255
451
|
# will execute before the action on this controller is performed.
|
|
256
452
|
def prepend_before_filter(*filters, &block)
|
|
257
|
-
prepend_filter_to_chain(filters, :before, &block)
|
|
453
|
+
filter_chain.prepend_filter_to_chain(filters, :before, &block)
|
|
258
454
|
end
|
|
259
455
|
|
|
260
456
|
# Shorthand for append_before_filter since it's the most common.
|
|
@@ -263,20 +459,19 @@ module ActionController #:nodoc:
|
|
|
263
459
|
# The passed <tt>filters</tt> will be appended to the array of filters
|
|
264
460
|
# that run _after_ actions on this controller are performed.
|
|
265
461
|
def append_after_filter(*filters, &block)
|
|
266
|
-
append_filter_to_chain(filters, :after, &block)
|
|
462
|
+
filter_chain.append_filter_to_chain(filters, :after, &block)
|
|
267
463
|
end
|
|
268
464
|
|
|
269
465
|
# The passed <tt>filters</tt> will be prepended to the array of filters
|
|
270
466
|
# that run _after_ actions on this controller are performed.
|
|
271
467
|
def prepend_after_filter(*filters, &block)
|
|
272
|
-
prepend_filter_to_chain(filters, :after, &block)
|
|
468
|
+
filter_chain.prepend_filter_to_chain(filters, :after, &block)
|
|
273
469
|
end
|
|
274
470
|
|
|
275
471
|
# Shorthand for append_after_filter since it's the most common.
|
|
276
472
|
alias :after_filter :append_after_filter
|
|
277
473
|
|
|
278
|
-
|
|
279
|
-
# If you append_around_filter A.new, B.new, the filter chain looks like
|
|
474
|
+
# If you <tt>append_around_filter A.new, B.new</tt>, the filter chain looks like
|
|
280
475
|
#
|
|
281
476
|
# B#before
|
|
282
477
|
# A#before
|
|
@@ -284,16 +479,13 @@ module ActionController #:nodoc:
|
|
|
284
479
|
# A#after
|
|
285
480
|
# B#after
|
|
286
481
|
#
|
|
287
|
-
# With around filters which yield to the action block,
|
|
482
|
+
# With around filters which yield to the action block, +before+ and +after+
|
|
288
483
|
# are the code before and after the yield.
|
|
289
484
|
def append_around_filter(*filters, &block)
|
|
290
|
-
filters,
|
|
291
|
-
filters.map { |f| proxy_before_and_after_filter(f) }.each do |filter|
|
|
292
|
-
append_filter_to_chain([filter, conditions])
|
|
293
|
-
end
|
|
485
|
+
filter_chain.append_filter_to_chain(filters, :around, &block)
|
|
294
486
|
end
|
|
295
487
|
|
|
296
|
-
# If you prepend_around_filter A.new, B.new
|
|
488
|
+
# If you <tt>prepend_around_filter A.new, B.new</tt>, the filter chain looks like:
|
|
297
489
|
#
|
|
298
490
|
# A#before
|
|
299
491
|
# B#before
|
|
@@ -301,16 +493,13 @@ module ActionController #:nodoc:
|
|
|
301
493
|
# B#after
|
|
302
494
|
# A#after
|
|
303
495
|
#
|
|
304
|
-
# With around filters which yield to the action block,
|
|
496
|
+
# With around filters which yield to the action block, +before+ and +after+
|
|
305
497
|
# are the code before and after the yield.
|
|
306
498
|
def prepend_around_filter(*filters, &block)
|
|
307
|
-
filters,
|
|
308
|
-
filters.map { |f| proxy_before_and_after_filter(f) }.each do |filter|
|
|
309
|
-
prepend_filter_to_chain([filter, conditions])
|
|
310
|
-
end
|
|
499
|
+
filter_chain.prepend_filter_to_chain(filters, :around, &block)
|
|
311
500
|
end
|
|
312
501
|
|
|
313
|
-
# Shorthand for append_around_filter since it's the most common.
|
|
502
|
+
# Shorthand for +append_around_filter+ since it's the most common.
|
|
314
503
|
alias :around_filter :append_around_filter
|
|
315
504
|
|
|
316
505
|
# Removes the specified filters from the +before+ filter chain. Note that this only works for skipping method-reference
|
|
@@ -320,7 +509,7 @@ module ActionController #:nodoc:
|
|
|
320
509
|
# You can control the actions to skip the filter for with the <tt>:only</tt> and <tt>:except</tt> options,
|
|
321
510
|
# just like when you apply the filters.
|
|
322
511
|
def skip_before_filter(*filters)
|
|
323
|
-
skip_filter_in_chain(*filters, &:before?)
|
|
512
|
+
filter_chain.skip_filter_in_chain(*filters, &:before?)
|
|
324
513
|
end
|
|
325
514
|
|
|
326
515
|
# Removes the specified filters from the +after+ filter chain. Note that this only works for skipping method-reference
|
|
@@ -330,7 +519,7 @@ module ActionController #:nodoc:
|
|
|
330
519
|
# You can control the actions to skip the filter for with the <tt>:only</tt> and <tt>:except</tt> options,
|
|
331
520
|
# just like when you apply the filters.
|
|
332
521
|
def skip_after_filter(*filters)
|
|
333
|
-
skip_filter_in_chain(*filters, &:after?)
|
|
522
|
+
filter_chain.skip_filter_in_chain(*filters, &:after?)
|
|
334
523
|
end
|
|
335
524
|
|
|
336
525
|
# Removes the specified filters from the filter chain. This only works for method reference (symbol)
|
|
@@ -340,336 +529,30 @@ module ActionController #:nodoc:
|
|
|
340
529
|
# You can control the actions to skip the filter for with the <tt>:only</tt> and <tt>:except</tt> options,
|
|
341
530
|
# just like when you apply the filters.
|
|
342
531
|
def skip_filter(*filters)
|
|
343
|
-
skip_filter_in_chain(*filters)
|
|
532
|
+
filter_chain.skip_filter_in_chain(*filters)
|
|
344
533
|
end
|
|
345
534
|
|
|
346
535
|
# Returns an array of Filter objects for this controller.
|
|
347
536
|
def filter_chain
|
|
348
|
-
read_inheritable_attribute(
|
|
537
|
+
if chain = read_inheritable_attribute('filter_chain')
|
|
538
|
+
return chain
|
|
539
|
+
else
|
|
540
|
+
write_inheritable_attribute('filter_chain', FilterChain.new)
|
|
541
|
+
return filter_chain
|
|
542
|
+
end
|
|
349
543
|
end
|
|
350
544
|
|
|
351
545
|
# Returns all the before filters for this class and all its ancestors.
|
|
352
546
|
# This method returns the actual filter that was assigned in the controller to maintain existing functionality.
|
|
353
547
|
def before_filters #:nodoc:
|
|
354
|
-
filter_chain.select(&:before?).map(&:
|
|
548
|
+
filter_chain.select(&:before?).map(&:method)
|
|
355
549
|
end
|
|
356
550
|
|
|
357
551
|
# Returns all the after filters for this class and all its ancestors.
|
|
358
552
|
# This method returns the actual filter that was assigned in the controller to maintain existing functionality.
|
|
359
553
|
def after_filters #:nodoc:
|
|
360
|
-
filter_chain.select(&:after?).map(&:
|
|
361
|
-
end
|
|
362
|
-
|
|
363
|
-
# Returns a mapping between filters and the actions that may run them.
|
|
364
|
-
def included_actions #:nodoc:
|
|
365
|
-
@included_actions ||= read_inheritable_attribute("included_actions") || {}
|
|
366
|
-
end
|
|
367
|
-
|
|
368
|
-
# Returns a mapping between filters and actions that may not run them.
|
|
369
|
-
def excluded_actions #:nodoc:
|
|
370
|
-
@excluded_actions ||= read_inheritable_attribute("excluded_actions") || {}
|
|
371
|
-
end
|
|
372
|
-
|
|
373
|
-
# Find a filter in the filter_chain where the filter method matches the _filter_ param
|
|
374
|
-
# and (optionally) the passed block evaluates to true (mostly used for testing before?
|
|
375
|
-
# and after? on the filter). Useful for symbol filters.
|
|
376
|
-
#
|
|
377
|
-
# The object of type Filter is passed to the block when yielded, not the filter itself.
|
|
378
|
-
def find_filter(filter, &block) #:nodoc:
|
|
379
|
-
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
|
-
case
|
|
385
|
-
when ia = included_actions[filter]
|
|
386
|
-
!ia.include?(action)
|
|
387
|
-
when ea = excluded_actions[filter]
|
|
388
|
-
ea.include?(action)
|
|
389
|
-
end
|
|
390
|
-
end
|
|
391
|
-
|
|
392
|
-
# Filter class is an abstract base class for all filters. Handles all of the included/excluded actions but
|
|
393
|
-
# contains no logic for calling the actual filters.
|
|
394
|
-
class Filter #:nodoc:
|
|
395
|
-
attr_reader :filter, :included_actions, :excluded_actions
|
|
396
|
-
|
|
397
|
-
def initialize(filter)
|
|
398
|
-
@filter = filter
|
|
399
|
-
end
|
|
400
|
-
|
|
401
|
-
def type
|
|
402
|
-
:around
|
|
403
|
-
end
|
|
404
|
-
|
|
405
|
-
def before?
|
|
406
|
-
type == :before
|
|
407
|
-
end
|
|
408
|
-
|
|
409
|
-
def after?
|
|
410
|
-
type == :after
|
|
411
|
-
end
|
|
412
|
-
|
|
413
|
-
def around?
|
|
414
|
-
type == :around
|
|
415
|
-
end
|
|
416
|
-
|
|
417
|
-
def run(controller)
|
|
418
|
-
raise ActionControllerError, 'No filter type: Nothing to do here.'
|
|
419
|
-
end
|
|
420
|
-
|
|
421
|
-
def call(controller, &block)
|
|
422
|
-
run(controller)
|
|
423
|
-
end
|
|
424
|
-
end
|
|
425
|
-
|
|
426
|
-
# Abstract base class for filter proxies. FilterProxy objects are meant to mimic the behaviour of the old
|
|
427
|
-
# before_filter and after_filter by moving the logic into the filter itself.
|
|
428
|
-
class FilterProxy < Filter #:nodoc:
|
|
429
|
-
def filter
|
|
430
|
-
@filter.filter
|
|
431
|
-
end
|
|
432
|
-
end
|
|
433
|
-
|
|
434
|
-
class BeforeFilterProxy < FilterProxy #:nodoc:
|
|
435
|
-
def type
|
|
436
|
-
:before
|
|
437
|
-
end
|
|
438
|
-
|
|
439
|
-
def run(controller)
|
|
440
|
-
# only filters returning false are halted.
|
|
441
|
-
@filter.call(controller)
|
|
442
|
-
if controller.send!(:performed?)
|
|
443
|
-
controller.send!(:halt_filter_chain, @filter, :rendered_or_redirected)
|
|
444
|
-
end
|
|
445
|
-
end
|
|
446
|
-
|
|
447
|
-
def call(controller)
|
|
448
|
-
yield unless run(controller)
|
|
449
|
-
end
|
|
450
|
-
end
|
|
451
|
-
|
|
452
|
-
class AfterFilterProxy < FilterProxy #:nodoc:
|
|
453
|
-
def type
|
|
454
|
-
:after
|
|
455
|
-
end
|
|
456
|
-
|
|
457
|
-
def run(controller)
|
|
458
|
-
@filter.call(controller)
|
|
459
|
-
end
|
|
460
|
-
|
|
461
|
-
def call(controller)
|
|
462
|
-
yield
|
|
463
|
-
run(controller)
|
|
464
|
-
end
|
|
465
|
-
end
|
|
466
|
-
|
|
467
|
-
class SymbolFilter < Filter #:nodoc:
|
|
468
|
-
def call(controller, &block)
|
|
469
|
-
controller.send!(@filter, &block)
|
|
470
|
-
end
|
|
471
|
-
end
|
|
472
|
-
|
|
473
|
-
class ProcFilter < Filter #:nodoc:
|
|
474
|
-
def call(controller)
|
|
475
|
-
@filter.call(controller)
|
|
476
|
-
rescue LocalJumpError # a yield from a proc... no no bad dog.
|
|
477
|
-
raise(ActionControllerError, 'Cannot yield from a Proc type filter. The Proc must take two arguments and execute #call on the second argument.')
|
|
478
|
-
end
|
|
479
|
-
end
|
|
480
|
-
|
|
481
|
-
class ProcWithCallFilter < Filter #:nodoc:
|
|
482
|
-
def call(controller, &block)
|
|
483
|
-
@filter.call(controller, block)
|
|
484
|
-
rescue LocalJumpError # a yield from a proc... no no bad dog.
|
|
485
|
-
raise(ActionControllerError, 'Cannot yield from a Proc type filter. The Proc must take two arguments and execute #call on the second argument.')
|
|
486
|
-
end
|
|
487
|
-
end
|
|
488
|
-
|
|
489
|
-
class MethodFilter < Filter #:nodoc:
|
|
490
|
-
def call(controller, &block)
|
|
491
|
-
@filter.call(controller, &block)
|
|
492
|
-
end
|
|
493
|
-
end
|
|
494
|
-
|
|
495
|
-
class ClassFilter < Filter #:nodoc:
|
|
496
|
-
def call(controller, &block)
|
|
497
|
-
@filter.filter(controller, &block)
|
|
498
|
-
end
|
|
499
|
-
end
|
|
500
|
-
|
|
501
|
-
class ClassBeforeFilter < Filter #:nodoc:
|
|
502
|
-
def call(controller, &block)
|
|
503
|
-
@filter.before(controller)
|
|
504
|
-
end
|
|
554
|
+
filter_chain.select(&:after?).map(&:method)
|
|
505
555
|
end
|
|
506
|
-
|
|
507
|
-
class ClassAfterFilter < Filter #:nodoc:
|
|
508
|
-
def call(controller, &block)
|
|
509
|
-
@filter.after(controller)
|
|
510
|
-
end
|
|
511
|
-
end
|
|
512
|
-
|
|
513
|
-
protected
|
|
514
|
-
def append_filter_to_chain(filters, filter_type = :around, &block)
|
|
515
|
-
pos = find_filter_append_position(filters, filter_type)
|
|
516
|
-
update_filter_chain(filters, filter_type, pos, &block)
|
|
517
|
-
end
|
|
518
|
-
|
|
519
|
-
def prepend_filter_to_chain(filters, filter_type = :around, &block)
|
|
520
|
-
pos = find_filter_prepend_position(filters, filter_type)
|
|
521
|
-
update_filter_chain(filters, filter_type, pos, &block)
|
|
522
|
-
end
|
|
523
|
-
|
|
524
|
-
def update_filter_chain(filters, filter_type, pos, &block)
|
|
525
|
-
new_filters = create_filters(filters, filter_type, &block)
|
|
526
|
-
new_chain = filter_chain.insert(pos, new_filters).flatten
|
|
527
|
-
write_inheritable_attribute('filter_chain', new_chain)
|
|
528
|
-
end
|
|
529
|
-
|
|
530
|
-
def find_filter_append_position(filters, filter_type)
|
|
531
|
-
# appending an after filter puts it at the end of the call chain
|
|
532
|
-
# before and around filters go before the first after filter in the chain
|
|
533
|
-
unless filter_type == :after
|
|
534
|
-
filter_chain.each_with_index do |f,i|
|
|
535
|
-
return i if f.after?
|
|
536
|
-
end
|
|
537
|
-
end
|
|
538
|
-
return -1
|
|
539
|
-
end
|
|
540
|
-
|
|
541
|
-
def find_filter_prepend_position(filters, filter_type)
|
|
542
|
-
# prepending a before or around filter puts it at the front of the call chain
|
|
543
|
-
# after filters go before the first after filter in the chain
|
|
544
|
-
if filter_type == :after
|
|
545
|
-
filter_chain.each_with_index do |f,i|
|
|
546
|
-
return i if f.after?
|
|
547
|
-
end
|
|
548
|
-
return -1
|
|
549
|
-
end
|
|
550
|
-
return 0
|
|
551
|
-
end
|
|
552
|
-
|
|
553
|
-
def create_filters(filters, filter_type, &block) #:nodoc:
|
|
554
|
-
filters, conditions = extract_conditions(filters, &block)
|
|
555
|
-
filters.map! { |filter| find_or_create_filter(filter, filter_type) }
|
|
556
|
-
update_conditions(filters, conditions)
|
|
557
|
-
filters
|
|
558
|
-
end
|
|
559
|
-
|
|
560
|
-
def find_or_create_filter(filter, filter_type)
|
|
561
|
-
if found_filter = find_filter(filter) { |f| f.type == filter_type }
|
|
562
|
-
found_filter
|
|
563
|
-
else
|
|
564
|
-
f = class_for_filter(filter, filter_type).new(filter)
|
|
565
|
-
# apply proxy to filter if necessary
|
|
566
|
-
case filter_type
|
|
567
|
-
when :before
|
|
568
|
-
BeforeFilterProxy.new(f)
|
|
569
|
-
when :after
|
|
570
|
-
AfterFilterProxy.new(f)
|
|
571
|
-
else
|
|
572
|
-
f
|
|
573
|
-
end
|
|
574
|
-
end
|
|
575
|
-
end
|
|
576
|
-
|
|
577
|
-
# The determination of the filter type was once done at run time.
|
|
578
|
-
# This method is here to extract as much logic from the filter run time as possible
|
|
579
|
-
def class_for_filter(filter, filter_type) #:nodoc:
|
|
580
|
-
case
|
|
581
|
-
when filter.is_a?(Symbol)
|
|
582
|
-
SymbolFilter
|
|
583
|
-
when filter.respond_to?(:call)
|
|
584
|
-
if filter.is_a?(Method)
|
|
585
|
-
MethodFilter
|
|
586
|
-
else
|
|
587
|
-
case filter.arity
|
|
588
|
-
when 1; ProcFilter
|
|
589
|
-
when 2; ProcWithCallFilter
|
|
590
|
-
else raise ArgumentError, 'Filter blocks must take one or two arguments.'
|
|
591
|
-
end
|
|
592
|
-
end
|
|
593
|
-
when filter.respond_to?(:filter)
|
|
594
|
-
ClassFilter
|
|
595
|
-
when filter.respond_to?(:before) && filter_type == :before
|
|
596
|
-
ClassBeforeFilter
|
|
597
|
-
when filter.respond_to?(:after) && filter_type == :after
|
|
598
|
-
ClassAfterFilter
|
|
599
|
-
else
|
|
600
|
-
raise(ActionControllerError, 'A filter must be a Symbol, Proc, Method, or object responding to filter, after or before.')
|
|
601
|
-
end
|
|
602
|
-
end
|
|
603
|
-
|
|
604
|
-
def extract_conditions(*filters, &block) #:nodoc:
|
|
605
|
-
filters.flatten!
|
|
606
|
-
conditions = filters.extract_options!
|
|
607
|
-
filters << block if block_given?
|
|
608
|
-
return filters, conditions
|
|
609
|
-
end
|
|
610
|
-
|
|
611
|
-
def update_conditions(filters, conditions)
|
|
612
|
-
return if conditions.empty?
|
|
613
|
-
if conditions[:only]
|
|
614
|
-
write_inheritable_hash('included_actions', condition_hash(filters, conditions[:only]))
|
|
615
|
-
elsif conditions[:except]
|
|
616
|
-
write_inheritable_hash('excluded_actions', condition_hash(filters, conditions[:except]))
|
|
617
|
-
end
|
|
618
|
-
end
|
|
619
|
-
|
|
620
|
-
def condition_hash(filters, *actions)
|
|
621
|
-
actions = actions.flatten.map(&:to_s)
|
|
622
|
-
filters.inject({}) { |h,f| h.update( f => (actions.blank? ? nil : actions)) }
|
|
623
|
-
end
|
|
624
|
-
|
|
625
|
-
def skip_filter_in_chain(*filters, &test) #:nodoc:
|
|
626
|
-
filters, conditions = extract_conditions(filters)
|
|
627
|
-
filters.map! { |f| block_given? ? find_filter(f, &test) : find_filter(f) }
|
|
628
|
-
filters.compact!
|
|
629
|
-
|
|
630
|
-
if conditions.empty?
|
|
631
|
-
delete_filters_in_chain(filters)
|
|
632
|
-
else
|
|
633
|
-
remove_actions_from_included_actions!(filters,conditions[:only] || [])
|
|
634
|
-
conditions[:only], conditions[:except] = conditions[:except], conditions[:only]
|
|
635
|
-
update_conditions(filters,conditions)
|
|
636
|
-
end
|
|
637
|
-
end
|
|
638
|
-
|
|
639
|
-
def remove_actions_from_included_actions!(filters,*actions)
|
|
640
|
-
actions = actions.flatten.map(&:to_s)
|
|
641
|
-
updated_hash = filters.inject(read_inheritable_attribute('included_actions')||{}) do |hash,filter|
|
|
642
|
-
ia = (hash[filter] || []) - actions
|
|
643
|
-
ia.empty? ? hash.delete(filter) : hash[filter] = ia
|
|
644
|
-
hash
|
|
645
|
-
end
|
|
646
|
-
write_inheritable_attribute('included_actions', updated_hash)
|
|
647
|
-
end
|
|
648
|
-
|
|
649
|
-
def delete_filters_in_chain(filters) #:nodoc:
|
|
650
|
-
write_inheritable_attribute('filter_chain', filter_chain.reject { |f| filters.include?(f) })
|
|
651
|
-
end
|
|
652
|
-
|
|
653
|
-
def filter_responds_to_before_and_after(filter) #:nodoc:
|
|
654
|
-
filter.respond_to?(:before) && filter.respond_to?(:after)
|
|
655
|
-
end
|
|
656
|
-
|
|
657
|
-
def proxy_before_and_after_filter(filter) #:nodoc:
|
|
658
|
-
return filter unless filter_responds_to_before_and_after(filter)
|
|
659
|
-
Proc.new do |controller, action|
|
|
660
|
-
filter.before(controller)
|
|
661
|
-
|
|
662
|
-
if controller.send!(:performed?)
|
|
663
|
-
controller.send!(:halt_filter_chain, filter, :rendered_or_redirected)
|
|
664
|
-
else
|
|
665
|
-
begin
|
|
666
|
-
action.call
|
|
667
|
-
ensure
|
|
668
|
-
filter.after(controller)
|
|
669
|
-
end
|
|
670
|
-
end
|
|
671
|
-
end
|
|
672
|
-
end
|
|
673
556
|
end
|
|
674
557
|
|
|
675
558
|
module InstanceMethods # :nodoc:
|
|
@@ -681,89 +564,80 @@ module ActionController #:nodoc:
|
|
|
681
564
|
end
|
|
682
565
|
|
|
683
566
|
protected
|
|
567
|
+
def process_with_filters(request, response, method = :perform_action, *arguments) #:nodoc:
|
|
568
|
+
@before_filter_chain_aborted = false
|
|
569
|
+
process_without_filters(request, response, method, *arguments)
|
|
570
|
+
end
|
|
684
571
|
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
end
|
|
689
|
-
|
|
690
|
-
def perform_action_with_filters
|
|
691
|
-
call_filters(self.class.filter_chain, 0, 0)
|
|
692
|
-
end
|
|
572
|
+
def perform_action_with_filters
|
|
573
|
+
call_filters(self.class.filter_chain, 0, 0)
|
|
574
|
+
end
|
|
693
575
|
|
|
694
576
|
private
|
|
577
|
+
def call_filters(chain, index, nesting)
|
|
578
|
+
index = run_before_filters(chain, index, nesting)
|
|
579
|
+
aborted = @before_filter_chain_aborted
|
|
580
|
+
perform_action_without_filters unless performed? || aborted
|
|
581
|
+
return index if nesting != 0 || aborted
|
|
582
|
+
run_after_filters(chain, index)
|
|
583
|
+
end
|
|
584
|
+
|
|
585
|
+
def run_before_filters(chain, index, nesting)
|
|
586
|
+
while chain[index]
|
|
587
|
+
filter, index = chain[index], index
|
|
588
|
+
break unless filter # end of call chain reached
|
|
589
|
+
|
|
590
|
+
case filter
|
|
591
|
+
when BeforeFilter
|
|
592
|
+
filter.call(self) # invoke before filter
|
|
593
|
+
index = index.next
|
|
594
|
+
break if @before_filter_chain_aborted
|
|
595
|
+
when AroundFilter
|
|
596
|
+
yielded = false
|
|
597
|
+
|
|
598
|
+
filter.call(self) do
|
|
599
|
+
yielded = true
|
|
600
|
+
# all remaining before and around filters will be run in this call
|
|
601
|
+
index = call_filters(chain, index.next, nesting.next)
|
|
602
|
+
end
|
|
695
603
|
|
|
696
|
-
|
|
697
|
-
index = run_before_filters(chain, index, nesting)
|
|
698
|
-
aborted = @before_filter_chain_aborted
|
|
699
|
-
perform_action_without_filters unless performed? || aborted
|
|
700
|
-
return index if nesting != 0 || aborted
|
|
701
|
-
run_after_filters(chain, index)
|
|
702
|
-
end
|
|
703
|
-
|
|
704
|
-
def skip_excluded_filters(chain, index)
|
|
705
|
-
while (filter = chain[index]) && self.class.filter_excluded_from_action?(filter, action_name)
|
|
706
|
-
index = index.next
|
|
707
|
-
end
|
|
708
|
-
[filter, index]
|
|
709
|
-
end
|
|
710
|
-
|
|
711
|
-
def run_before_filters(chain, index, nesting)
|
|
712
|
-
while chain[index]
|
|
713
|
-
filter, index = skip_excluded_filters(chain, index)
|
|
714
|
-
break unless filter # end of call chain reached
|
|
604
|
+
halt_filter_chain(filter, :did_not_yield) unless yielded
|
|
715
605
|
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
index = index.next
|
|
720
|
-
break if @before_filter_chain_aborted
|
|
721
|
-
when :around
|
|
722
|
-
yielded = false
|
|
723
|
-
|
|
724
|
-
filter.call(self) do
|
|
725
|
-
yielded = true
|
|
726
|
-
# all remaining before and around filters will be run in this call
|
|
727
|
-
index = call_filters(chain, index.next, nesting.next)
|
|
606
|
+
break
|
|
607
|
+
else
|
|
608
|
+
break # no before or around filters left
|
|
728
609
|
end
|
|
729
|
-
|
|
730
|
-
halt_filter_chain(filter, :did_not_yield) unless yielded
|
|
731
|
-
|
|
732
|
-
break
|
|
733
|
-
else
|
|
734
|
-
break # no before or around filters left
|
|
735
610
|
end
|
|
611
|
+
|
|
612
|
+
index
|
|
736
613
|
end
|
|
737
614
|
|
|
738
|
-
index
|
|
739
|
-
|
|
615
|
+
def run_after_filters(chain, index)
|
|
616
|
+
seen_after_filter = false
|
|
740
617
|
|
|
741
|
-
|
|
742
|
-
|
|
618
|
+
while chain[index]
|
|
619
|
+
filter, index = chain[index], index
|
|
620
|
+
break unless filter # end of call chain reached
|
|
743
621
|
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
622
|
+
case filter
|
|
623
|
+
when AfterFilter
|
|
624
|
+
seen_after_filter = true
|
|
625
|
+
filter.call(self) # invoke after filter
|
|
626
|
+
else
|
|
627
|
+
# implementation error or someone has mucked with the filter chain
|
|
628
|
+
raise ActionControllerError, "filter #{filter.inspect} was in the wrong place!" if seen_after_filter
|
|
629
|
+
end
|
|
747
630
|
|
|
748
|
-
|
|
749
|
-
when :after
|
|
750
|
-
seen_after_filter = true
|
|
751
|
-
filter.run(self) # invoke after filter
|
|
752
|
-
else
|
|
753
|
-
# implementation error or someone has mucked with the filter chain
|
|
754
|
-
raise ActionControllerError, "filter #{filter.inspect} was in the wrong place!" if seen_after_filter
|
|
631
|
+
index = index.next
|
|
755
632
|
end
|
|
756
633
|
|
|
757
|
-
index
|
|
634
|
+
index.next
|
|
758
635
|
end
|
|
759
636
|
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
@before_filter_chain_aborted = true
|
|
765
|
-
logger.info "Filter chain halted as [#{filter.inspect}] #{reason}." if logger
|
|
766
|
-
end
|
|
637
|
+
def halt_filter_chain(filter, reason)
|
|
638
|
+
@before_filter_chain_aborted = true
|
|
639
|
+
logger.info "Filter chain halted as [#{filter.inspect}] #{reason}." if logger
|
|
640
|
+
end
|
|
767
641
|
end
|
|
768
642
|
end
|
|
769
643
|
end
|