actionpack 1.13.6 → 2.0.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of actionpack might be problematic. Click here for more details.
- data/CHANGELOG +1400 -20
- data/MIT-LICENSE +1 -1
- data/README +5 -5
- data/RUNNING_UNIT_TESTS +4 -5
- data/Rakefile +5 -6
- data/install.rb +2 -2
- data/lib/action_controller.rb +11 -15
- data/lib/action_controller/assertions.rb +12 -25
- data/lib/action_controller/assertions/dom_assertions.rb +18 -4
- data/lib/action_controller/assertions/model_assertions.rb +8 -1
- data/lib/action_controller/assertions/response_assertions.rb +35 -12
- data/lib/action_controller/assertions/routing_assertions.rb +56 -12
- data/lib/action_controller/assertions/selector_assertions.rb +105 -38
- data/lib/action_controller/assertions/tag_assertions.rb +28 -15
- data/lib/action_controller/base.rb +318 -250
- data/lib/action_controller/benchmarking.rb +33 -29
- data/lib/action_controller/caching.rb +130 -64
- data/lib/action_controller/cgi_ext.rb +16 -0
- data/lib/action_controller/cgi_ext/{cookie_performance_fix.rb → cookie.rb} +25 -40
- data/lib/action_controller/cgi_ext/query_extension.rb +22 -0
- data/lib/action_controller/cgi_ext/session.rb +73 -0
- data/lib/action_controller/cgi_ext/stdinput.rb +23 -0
- data/lib/action_controller/cgi_process.rb +34 -57
- data/lib/action_controller/components.rb +19 -36
- data/lib/action_controller/cookies.rb +10 -9
- data/lib/action_controller/dispatcher.rb +195 -0
- data/lib/action_controller/filters.rb +35 -34
- data/lib/action_controller/flash.rb +30 -35
- data/lib/action_controller/helpers.rb +121 -47
- data/lib/action_controller/http_authentication.rb +126 -0
- data/lib/action_controller/integration.rb +105 -101
- data/lib/action_controller/layout.rb +59 -47
- data/lib/action_controller/mime_responds.rb +57 -68
- data/lib/action_controller/mime_type.rb +43 -80
- data/lib/action_controller/mime_types.rb +20 -0
- data/lib/action_controller/polymorphic_routes.rb +88 -0
- data/lib/action_controller/record_identifier.rb +91 -0
- data/lib/action_controller/request.rb +553 -88
- data/lib/action_controller/request_forgery_protection.rb +126 -0
- data/lib/action_controller/request_profiler.rb +138 -0
- data/lib/action_controller/rescue.rb +185 -69
- data/lib/action_controller/resources.rb +211 -172
- data/lib/action_controller/response.rb +49 -8
- data/lib/action_controller/routing.rb +359 -236
- data/lib/action_controller/routing_optimisation.rb +119 -0
- data/lib/action_controller/session/active_record_store.rb +3 -2
- data/lib/action_controller/session/cookie_store.rb +161 -0
- data/lib/action_controller/session/mem_cache_store.rb +9 -16
- data/lib/action_controller/session_management.rb +17 -8
- data/lib/action_controller/streaming.rb +6 -3
- data/lib/action_controller/templates/rescues/_request_and_response.erb +24 -0
- data/lib/action_controller/templates/rescues/{_trace.rhtml → _trace.erb} +0 -0
- data/lib/action_controller/templates/rescues/{diagnostics.rhtml → diagnostics.erb} +2 -2
- data/lib/action_controller/templates/rescues/{layout.rhtml → layout.erb} +0 -0
- data/lib/action_controller/templates/rescues/{missing_template.rhtml → missing_template.erb} +0 -0
- data/lib/action_controller/templates/rescues/{routing_error.rhtml → routing_error.erb} +0 -0
- data/lib/action_controller/templates/rescues/{template_error.rhtml → template_error.erb} +2 -2
- data/lib/action_controller/templates/rescues/{unknown_action.rhtml → unknown_action.erb} +0 -0
- data/lib/action_controller/test_case.rb +53 -0
- data/lib/action_controller/test_process.rb +59 -46
- data/lib/action_controller/url_rewriter.rb +48 -24
- data/lib/action_controller/vendor/html-scanner/html/document.rb +7 -4
- data/lib/action_controller/vendor/html-scanner/html/sanitizer.rb +173 -0
- data/lib/action_controller/vendor/html-scanner/html/selector.rb +11 -6
- data/lib/action_controller/verification.rb +27 -21
- data/lib/action_pack.rb +1 -1
- data/lib/action_pack/version.rb +4 -4
- data/lib/action_view.rb +2 -3
- data/lib/action_view/base.rb +218 -63
- data/lib/action_view/compiled_templates.rb +1 -2
- data/lib/action_view/helpers/active_record_helper.rb +35 -17
- data/lib/action_view/helpers/asset_tag_helper.rb +395 -87
- data/lib/action_view/helpers/atom_feed_helper.rb +111 -0
- data/lib/action_view/helpers/benchmark_helper.rb +12 -5
- data/lib/action_view/helpers/cache_helper.rb +29 -0
- data/lib/action_view/helpers/capture_helper.rb +97 -63
- data/lib/action_view/helpers/date_helper.rb +295 -35
- data/lib/action_view/helpers/debug_helper.rb +6 -2
- data/lib/action_view/helpers/form_helper.rb +354 -111
- data/lib/action_view/helpers/form_options_helper.rb +171 -109
- data/lib/action_view/helpers/form_tag_helper.rb +332 -76
- data/lib/action_view/helpers/javascript_helper.rb +35 -11
- data/lib/action_view/helpers/javascripts/controls.js +484 -354
- data/lib/action_view/helpers/javascripts/dragdrop.js +88 -58
- data/lib/action_view/helpers/javascripts/effects.js +396 -364
- data/lib/action_view/helpers/javascripts/prototype.js +2817 -1107
- data/lib/action_view/helpers/number_helper.rb +84 -60
- data/lib/action_view/helpers/prototype_helper.rb +419 -43
- data/lib/action_view/helpers/record_identification_helper.rb +20 -0
- data/lib/action_view/helpers/record_tag_helper.rb +59 -0
- data/lib/action_view/helpers/sanitize_helper.rb +223 -0
- data/lib/action_view/helpers/scriptaculous_helper.rb +63 -4
- data/lib/action_view/helpers/tag_helper.rb +69 -39
- data/lib/action_view/helpers/text_helper.rb +221 -148
- data/lib/action_view/helpers/url_helper.rb +283 -165
- data/lib/action_view/partials.rb +134 -62
- data/lib/action_view/template_error.rb +4 -12
- data/lib/actionpack.rb +1 -0
- data/test/abstract_unit.rb +21 -1
- data/test/action_view_test.rb +26 -0
- data/test/active_record_unit.rb +12 -20
- data/test/activerecord/active_record_store_test.rb +2 -2
- data/test/activerecord/render_partial_with_record_identification_test.rb +74 -0
- data/test/controller/action_pack_assertions_test.rb +21 -152
- data/test/controller/addresses_render_test.rb +2 -7
- data/test/controller/assert_select_test.rb +120 -14
- data/test/controller/base_test.rb +11 -13
- data/test/controller/caching_test.rb +125 -5
- data/test/controller/capture_test.rb +23 -16
- data/test/controller/cgi_test.rb +66 -391
- data/test/controller/components_test.rb +31 -42
- data/test/controller/content_type_test.rb +1 -1
- data/test/controller/cookie_test.rb +42 -14
- data/test/controller/deprecation/deprecated_base_methods_test.rb +1 -42
- data/test/controller/dispatcher_test.rb +123 -0
- data/test/controller/fake_models.rb +5 -0
- data/test/controller/filters_test.rb +44 -7
- data/test/controller/flash_test.rb +46 -2
- data/test/controller/fragment_store_setting_test.rb +10 -8
- data/test/controller/helper_test.rb +19 -2
- data/test/controller/html-scanner/document_test.rb +124 -0
- data/test/controller/html-scanner/node_test.rb +69 -0
- data/test/controller/html-scanner/sanitizer_test.rb +250 -0
- data/test/controller/html-scanner/tag_node_test.rb +239 -0
- data/test/controller/html-scanner/text_node_test.rb +51 -0
- data/test/controller/html-scanner/tokenizer_test.rb +125 -0
- data/test/controller/http_authentication_test.rb +54 -0
- data/test/controller/integration_test.rb +12 -26
- data/test/controller/layout_test.rb +64 -12
- data/test/controller/mime_responds_test.rb +193 -38
- data/test/controller/mime_type_test.rb +30 -8
- data/test/controller/new_render_test.rb +104 -22
- data/test/controller/polymorphic_routes_test.rb +98 -0
- data/test/controller/record_identifier_test.rb +103 -0
- data/test/controller/redirect_test.rb +120 -18
- data/test/controller/render_test.rb +195 -45
- data/test/controller/request_forgery_protection_test.rb +217 -0
- data/test/controller/request_test.rb +545 -27
- data/test/controller/rescue_test.rb +501 -0
- data/test/controller/resources_test.rb +258 -132
- data/test/controller/routing_test.rb +502 -106
- data/test/controller/selector_test.rb +5 -5
- data/test/controller/send_file_test.rb +17 -7
- data/test/controller/session/cookie_store_test.rb +246 -0
- data/test/controller/session/mem_cache_store_test.rb +182 -0
- data/test/controller/session_fixation_test.rb +8 -11
- data/test/controller/session_management_test.rb +7 -7
- data/test/controller/test_test.rb +150 -38
- data/test/controller/url_rewriter_test.rb +87 -12
- data/test/controller/verification_test.rb +11 -0
- data/test/controller/view_paths_test.rb +137 -0
- data/test/controller/webservice_test.rb +11 -75
- data/test/fixtures/addresses/{list.rhtml → list.erb} +0 -0
- data/test/fixtures/db_definitions/sqlite.sql +2 -1
- data/test/fixtures/developer.rb +2 -0
- data/test/fixtures/fun/games/{hello_world.rhtml → hello_world.erb} +0 -0
- data/test/fixtures/helpers/fun/pdf_helper.rb +1 -1
- data/test/fixtures/layout_tests/alt/hello.rhtml +1 -0
- data/test/fixtures/layout_tests/layouts/multiple_extensions.html.erb +1 -0
- data/test/fixtures/layouts/{builder.rxml → builder.builder} +0 -0
- data/test/fixtures/layouts/{standard.rhtml → standard.erb} +0 -0
- data/test/fixtures/layouts/{talk_from_action.rhtml → talk_from_action.erb} +0 -0
- data/test/fixtures/layouts/{yield.rhtml → yield.erb} +0 -0
- data/test/fixtures/multipart/binary_file +0 -0
- data/test/fixtures/multipart/bracketed_param +5 -0
- data/test/fixtures/override/test/hello_world.erb +1 -0
- data/test/fixtures/override2/layouts/test/sub.erb +1 -0
- data/test/fixtures/post_test/layouts/post.html.erb +1 -0
- data/test/fixtures/post_test/layouts/super_post.iphone.erb +1 -0
- data/test/fixtures/post_test/post/index.html.erb +1 -0
- data/test/fixtures/post_test/post/index.iphone.erb +1 -0
- data/test/fixtures/post_test/super_post/index.html.erb +1 -0
- data/test/fixtures/post_test/super_post/index.iphone.erb +1 -0
- data/test/fixtures/public/404.html +1 -0
- data/test/fixtures/public/500.html +1 -0
- data/test/fixtures/public/javascripts/application.js +0 -1
- data/test/fixtures/public/javascripts/bank.js +1 -0
- data/test/fixtures/public/javascripts/robber.js +1 -0
- data/test/fixtures/public/stylesheets/bank.css +1 -0
- data/test/fixtures/public/stylesheets/robber.css +1 -0
- data/test/fixtures/replies.yml +2 -0
- data/test/fixtures/reply.rb +2 -1
- data/test/fixtures/respond_to/{all_types_with_layout.rhtml → all_types_with_layout.html.erb} +0 -0
- data/test/fixtures/respond_to/{all_types_with_layout.rjs → all_types_with_layout.js.rjs} +0 -0
- data/test/fixtures/respond_to/custom_constant_handling_without_block.mobile.erb +1 -0
- data/test/fixtures/respond_to/iphone_with_html_response_type.html.erb +1 -0
- data/test/fixtures/respond_to/iphone_with_html_response_type.iphone.erb +1 -0
- data/test/fixtures/respond_to/layouts/missing.html.erb +1 -0
- data/test/fixtures/respond_to/layouts/standard.html.erb +1 -0
- data/test/fixtures/respond_to/layouts/standard.iphone.erb +1 -0
- data/test/fixtures/respond_to/{using_defaults.rhtml → using_defaults.html.erb} +0 -0
- data/test/fixtures/respond_to/{using_defaults.rjs → using_defaults.js.rjs} +0 -0
- data/test/fixtures/respond_to/{using_defaults.rxml → using_defaults.xml.builder} +0 -0
- data/test/fixtures/respond_to/{using_defaults_with_type_list.rhtml → using_defaults_with_type_list.html.erb} +0 -0
- data/test/fixtures/respond_to/{using_defaults_with_type_list.rjs → using_defaults_with_type_list.js.rjs} +0 -0
- data/test/fixtures/respond_to/{using_defaults_with_type_list.rxml → using_defaults_with_type_list.xml.builder} +0 -0
- data/test/fixtures/scope/test/{modgreet.rhtml → modgreet.erb} +0 -0
- data/test/fixtures/test/{_customer.rhtml → _customer.erb} +0 -0
- data/test/fixtures/test/{_customer_greeting.rhtml → _customer_greeting.erb} +0 -0
- data/test/fixtures/test/_hash_greeting.erb +1 -0
- data/test/fixtures/test/_hash_object.erb +2 -0
- data/test/fixtures/test/{_hello.rxml → _hello.builder} +0 -0
- data/test/fixtures/test/_layout_for_partial.html.erb +3 -0
- data/test/fixtures/test/_partial.erb +1 -0
- data/test/fixtures/test/_partial.html.erb +1 -0
- data/test/fixtures/test/_partial.js.erb +1 -0
- data/test/fixtures/test/_partial_for_use_in_layout.html.erb +1 -0
- data/test/fixtures/test/{_partial_only.rhtml → _partial_only.erb} +0 -0
- data/test/fixtures/test/{_person.rhtml → _person.erb} +0 -0
- data/test/fixtures/test/{action_talk_to_layout.rhtml → action_talk_to_layout.erb} +0 -0
- data/test/fixtures/test/{block_content_for.rhtml → block_content_for.erb} +0 -0
- data/test/fixtures/test/calling_partial_with_layout.html.erb +1 -0
- data/test/fixtures/test/{capturing.rhtml → capturing.erb} +0 -0
- data/test/fixtures/test/{content_for.rhtml → content_for.erb} +0 -0
- data/test/fixtures/test/content_for_concatenated.erb +3 -0
- data/test/fixtures/test/content_for_with_parameter.erb +2 -0
- data/test/fixtures/test/dot.directory/{render_file_with_ivar.rhtml → render_file_with_ivar.erb} +0 -0
- data/test/fixtures/test/{erb_content_for.rhtml → erb_content_for.erb} +0 -0
- data/test/fixtures/test/formatted_html_erb.html.erb +1 -0
- data/test/fixtures/test/formatted_xml_erb.builder +1 -0
- data/test/fixtures/test/formatted_xml_erb.html.erb +1 -0
- data/test/fixtures/test/formatted_xml_erb.xml.erb +1 -0
- data/test/fixtures/test/{greeting.rhtml → greeting.erb} +0 -0
- data/test/fixtures/test/{hello.rxml → hello.builder} +0 -0
- data/test/fixtures/test/{hello_world.rxml → hello_world.builder} +0 -0
- data/test/fixtures/test/{hello_world.rhtml → hello_world.erb} +0 -0
- data/test/fixtures/test/{hello_world_container.rxml → hello_world_container.builder} +0 -0
- data/test/fixtures/test/{hello_world_with_layout_false.rhtml → hello_world_with_layout_false.erb} +0 -0
- data/test/fixtures/test/{hello_xml_world.rxml → hello_xml_world.builder} +0 -0
- data/test/fixtures/test/list.erb +1 -0
- data/test/fixtures/test/{non_erb_block_content_for.rxml → non_erb_block_content_for.builder} +0 -0
- data/test/fixtures/test/{potential_conflicts.rhtml → potential_conflicts.erb} +0 -0
- data/test/fixtures/test/{render_file_with_ivar.rhtml → render_file_with_ivar.erb} +0 -0
- data/test/fixtures/test/{render_file_with_locals.rhtml → render_file_with_locals.erb} +0 -0
- data/test/fixtures/test/{render_to_string_test.rhtml → render_to_string_test.erb} +0 -0
- data/test/fixtures/test/{update_element_with_capture.rhtml → update_element_with_capture.erb} +0 -0
- data/test/fixtures/test/using_layout_around_block.html.erb +1 -0
- data/test/fixtures/topic.rb +1 -1
- data/test/template/active_record_helper_test.rb +67 -20
- data/test/template/asset_tag_helper_test.rb +222 -54
- data/test/template/atom_feed_helper_test.rb +101 -0
- data/test/template/benchmark_helper_test.rb +2 -2
- data/test/template/compiled_templates_test.rb +76 -32
- data/test/template/date_helper_test.rb +125 -9
- data/test/template/form_helper_test.rb +326 -33
- data/test/template/form_options_helper_test.rb +822 -15
- data/test/template/form_tag_helper_test.rb +96 -30
- data/test/template/javascript_helper_test.rb +61 -13
- data/test/template/number_helper_test.rb +12 -11
- data/test/template/prototype_helper_test.rb +185 -24
- data/test/template/sanitize_helper_test.rb +49 -0
- data/test/template/scriptaculous_helper_test.rb +9 -3
- data/test/template/tag_helper_test.rb +13 -2
- data/test/template/text_helper_test.rb +38 -52
- data/test/template/url_helper_test.rb +216 -46
- metadata +144 -116
- data/examples/.htaccess +0 -24
- data/examples/address_book/index.rhtml +0 -33
- data/examples/address_book/layout.rhtml +0 -8
- data/examples/address_book_controller.cgi +0 -9
- data/examples/address_book_controller.fcgi +0 -6
- data/examples/address_book_controller.rb +0 -52
- data/examples/address_book_controller.rbx +0 -4
- data/examples/benchmark.rb +0 -52
- data/examples/benchmark_with_ar.fcgi +0 -89
- data/examples/blog_controller.cgi +0 -53
- data/examples/debate/index.rhtml +0 -14
- data/examples/debate/new_topic.rhtml +0 -22
- data/examples/debate/topic.rhtml +0 -32
- data/examples/debate_controller.cgi +0 -57
- data/lib/action_controller/assertions/deprecated_assertions.rb +0 -228
- data/lib/action_controller/cgi_ext/cgi_ext.rb +0 -36
- data/lib/action_controller/cgi_ext/cgi_methods.rb +0 -211
- data/lib/action_controller/cgi_ext/pstore_performance_fix.rb +0 -30
- data/lib/action_controller/cgi_ext/raw_post_data_fix.rb +0 -95
- data/lib/action_controller/cgi_ext/session_performance_fix.rb +0 -30
- data/lib/action_controller/deprecated_dependencies.rb +0 -65
- data/lib/action_controller/deprecated_redirects.rb +0 -17
- data/lib/action_controller/deprecated_request_methods.rb +0 -34
- data/lib/action_controller/macros/auto_complete.rb +0 -53
- data/lib/action_controller/macros/in_place_editing.rb +0 -33
- data/lib/action_controller/pagination.rb +0 -408
- data/lib/action_controller/scaffolding.rb +0 -189
- data/lib/action_controller/templates/rescues/_request_and_response.rhtml +0 -44
- data/lib/action_controller/templates/scaffolds/edit.rhtml +0 -7
- data/lib/action_controller/templates/scaffolds/layout.rhtml +0 -69
- data/lib/action_controller/templates/scaffolds/list.rhtml +0 -27
- data/lib/action_controller/templates/scaffolds/new.rhtml +0 -6
- data/lib/action_controller/templates/scaffolds/show.rhtml +0 -9
- data/lib/action_controller/vendor/xml_node.rb +0 -97
- data/lib/action_view/helpers/deprecated_helper.rb +0 -37
- data/lib/action_view/helpers/java_script_macros_helper.rb +0 -233
- data/lib/action_view/helpers/pagination_helper.rb +0 -86
- data/test/activerecord/active_record_assertions_test.rb +0 -92
- data/test/activerecord/pagination_test.rb +0 -165
- data/test/controller/deprecated_instance_variables_test.rb +0 -48
- data/test/controller/raw_post_test.rb +0 -68
- data/test/fixtures/deprecated_instance_variables/_cookies_ivar.rhtml +0 -1
- data/test/fixtures/deprecated_instance_variables/_cookies_method.rhtml +0 -1
- data/test/fixtures/deprecated_instance_variables/_flash_ivar.rhtml +0 -1
- data/test/fixtures/deprecated_instance_variables/_flash_method.rhtml +0 -1
- data/test/fixtures/deprecated_instance_variables/_headers_ivar.rhtml +0 -1
- data/test/fixtures/deprecated_instance_variables/_headers_method.rhtml +0 -1
- data/test/fixtures/deprecated_instance_variables/_params_ivar.rhtml +0 -1
- data/test/fixtures/deprecated_instance_variables/_params_method.rhtml +0 -1
- data/test/fixtures/deprecated_instance_variables/_request_ivar.rhtml +0 -1
- data/test/fixtures/deprecated_instance_variables/_request_method.rhtml +0 -1
- data/test/fixtures/deprecated_instance_variables/_response_ivar.rhtml +0 -1
- data/test/fixtures/deprecated_instance_variables/_response_method.rhtml +0 -1
- data/test/fixtures/deprecated_instance_variables/_session_ivar.rhtml +0 -1
- data/test/fixtures/deprecated_instance_variables/_session_method.rhtml +0 -1
- data/test/fixtures/respond_to/layouts/standard.rhtml +0 -1
- data/test/fixtures/test/_hash_object.rhtml +0 -1
- data/test/fixtures/test/list.rhtml +0 -1
- data/test/template/deprecated_helper_test.rb +0 -36
- data/test/template/deprecated_instance_variables_test.rb +0 -43
- data/test/template/java_script_macros_helper_test.rb +0 -109
@@ -40,40 +40,44 @@ module ActionController #:nodoc:
|
|
40
40
|
end
|
41
41
|
end
|
42
42
|
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
43
|
+
protected
|
44
|
+
def render_with_benchmark(options = nil, deprecated_status = nil, &block)
|
45
|
+
unless logger
|
46
|
+
render_without_benchmark(options, &block)
|
47
|
+
else
|
48
|
+
db_runtime = ActiveRecord::Base.connection.reset_runtime if Object.const_defined?("ActiveRecord") && ActiveRecord::Base.connected?
|
49
|
+
|
50
|
+
render_output = nil
|
51
|
+
@rendering_runtime = Benchmark::measure{ render_output = render_without_benchmark(options, &block) }.real
|
48
52
|
|
49
|
-
|
50
|
-
|
53
|
+
if Object.const_defined?("ActiveRecord") && ActiveRecord::Base.connected?
|
54
|
+
@db_rt_before_render = db_runtime
|
55
|
+
@db_rt_after_render = ActiveRecord::Base.connection.reset_runtime
|
56
|
+
@rendering_runtime -= @db_rt_after_render
|
57
|
+
end
|
51
58
|
|
52
|
-
|
53
|
-
@db_rt_before_render = db_runtime
|
54
|
-
@db_rt_after_render = ActiveRecord::Base.connection.reset_runtime
|
55
|
-
@rendering_runtime -= @db_rt_after_render
|
59
|
+
render_output
|
56
60
|
end
|
61
|
+
end
|
57
62
|
|
58
|
-
|
59
|
-
|
60
|
-
|
63
|
+
private
|
64
|
+
def perform_action_with_benchmark
|
65
|
+
unless logger
|
66
|
+
perform_action_without_benchmark
|
67
|
+
else
|
68
|
+
runtime = [ Benchmark::measure{ perform_action_without_benchmark }.real, 0.0001 ].max
|
61
69
|
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
log_message << " [#{complete_request_uri rescue "unknown"}]"
|
72
|
-
logger.info(log_message)
|
70
|
+
log_message = "Completed in #{sprintf("%.5f", runtime)} (#{(1 / runtime).floor} reqs/sec)"
|
71
|
+
log_message << rendering_runtime(runtime) if defined?(@rendering_runtime)
|
72
|
+
log_message << active_record_runtime(runtime) if Object.const_defined?("ActiveRecord") && ActiveRecord::Base.connected?
|
73
|
+
log_message << " | #{headers["Status"]}"
|
74
|
+
log_message << " [#{complete_request_uri rescue "unknown"}]"
|
75
|
+
|
76
|
+
logger.info(log_message)
|
77
|
+
response.headers["X-Runtime"] = sprintf("%.5f", runtime)
|
78
|
+
end
|
73
79
|
end
|
74
|
-
|
75
|
-
|
76
|
-
private
|
80
|
+
|
77
81
|
def rendering_runtime(runtime)
|
78
82
|
" | Rendering: #{sprintf("%.5f", @rendering_runtime)} (#{sprintf("%d", (@rendering_runtime * 100) / runtime)}%)"
|
79
83
|
end
|
@@ -86,4 +90,4 @@ module ActionController #:nodoc:
|
|
86
90
|
" | DB: #{sprintf("%.5f", db_runtime)} (#{sprintf("%d", db_percentage)}%)"
|
87
91
|
end
|
88
92
|
end
|
89
|
-
end
|
93
|
+
end
|
@@ -11,9 +11,13 @@ module ActionController #:nodoc:
|
|
11
11
|
# Note: To turn off all caching and sweeping, set Base.perform_caching = false.
|
12
12
|
module Caching
|
13
13
|
def self.included(base) #:nodoc:
|
14
|
-
base.send(:include, Pages, Actions, Fragments, Sweeping)
|
15
|
-
|
16
14
|
base.class_eval do
|
15
|
+
include Pages, Actions, Fragments
|
16
|
+
|
17
|
+
if defined? ActiveRecord
|
18
|
+
include Sweeping, SqlCache
|
19
|
+
end
|
20
|
+
|
17
21
|
@@perform_caching = true
|
18
22
|
cattr_accessor :perform_caching
|
19
23
|
end
|
@@ -96,14 +100,13 @@ module ActionController #:nodoc:
|
|
96
100
|
# matches the triggering url.
|
97
101
|
def caches_page(*actions)
|
98
102
|
return unless perform_caching
|
99
|
-
actions
|
100
|
-
|
101
|
-
end
|
103
|
+
actions = actions.map(&:to_s)
|
104
|
+
after_filter { |c| c.cache_page if actions.include?(c.action_name) }
|
102
105
|
end
|
103
106
|
|
104
107
|
private
|
105
108
|
def page_cache_file(path)
|
106
|
-
name = (
|
109
|
+
name = (path.empty? || path == "/") ? "/index" : URI.unescape(path.chomp('/'))
|
107
110
|
name << page_cache_extension unless (name.split('/').last || name).include? '.'
|
108
111
|
return name
|
109
112
|
end
|
@@ -117,21 +120,36 @@ module ActionController #:nodoc:
|
|
117
120
|
# expire_page :controller => "lists", :action => "show"
|
118
121
|
def expire_page(options = {})
|
119
122
|
return unless perform_caching
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
+
|
124
|
+
if options.is_a?(Hash)
|
125
|
+
if options[:action].is_a?(Array)
|
126
|
+
options[:action].dup.each do |action|
|
127
|
+
self.class.expire_page(url_for(options.merge(:only_path => true, :skip_relative_url_root => true, :action => action)))
|
128
|
+
end
|
129
|
+
else
|
130
|
+
self.class.expire_page(url_for(options.merge(:only_path => true, :skip_relative_url_root => true)))
|
123
131
|
end
|
124
132
|
else
|
125
|
-
self.class.expire_page(
|
133
|
+
self.class.expire_page(options)
|
126
134
|
end
|
127
135
|
end
|
128
136
|
|
129
137
|
# Manually cache the +content+ in the key determined by +options+. If no content is provided, the contents of response.body is used
|
130
|
-
# If no options are provided, the
|
138
|
+
# If no options are provided, the requested url is used. Example:
|
131
139
|
# cache_page "I'm the cached content", :controller => "lists", :action => "show"
|
132
|
-
def cache_page(content = nil, options =
|
140
|
+
def cache_page(content = nil, options = nil)
|
133
141
|
return unless perform_caching && caching_allowed
|
134
|
-
|
142
|
+
|
143
|
+
path = case options
|
144
|
+
when Hash
|
145
|
+
url_for(options.merge(:only_path => true, :skip_relative_url_root => true, :format => params[:format]))
|
146
|
+
when String
|
147
|
+
options
|
148
|
+
else
|
149
|
+
request.path
|
150
|
+
end
|
151
|
+
|
152
|
+
self.class.cache_page(content || response.body, path)
|
135
153
|
end
|
136
154
|
|
137
155
|
private
|
@@ -161,17 +179,26 @@ module ActionController #:nodoc:
|
|
161
179
|
# Different representations of the same resource, e.g. <tt>http://david.somewhere.com/lists</tt> and <tt>http://david.somewhere.com/lists.xml</tt>
|
162
180
|
# are treated like separate requests and so are cached separately. Keep in mind when expiring an action cache that <tt>:action => 'lists'</tt> is not the same
|
163
181
|
# as <tt>:action => 'list', :format => :xml</tt>.
|
182
|
+
#
|
183
|
+
# You can set modify the default action cache path by passing a :cache_path option. This will be passed directly to ActionCachePath.path_for. This is handy
|
184
|
+
# for actions with multiple possible routes that should be cached differently. If a block is given, it is called with the current controller instance.
|
185
|
+
#
|
186
|
+
# class ListsController < ApplicationController
|
187
|
+
# before_filter :authenticate, :except => :public
|
188
|
+
# caches_page :public
|
189
|
+
# caches_action :show, :cache_path => { :project => 1 }
|
190
|
+
# caches_action :show, :cache_path => Proc.new { |controller|
|
191
|
+
# controller.params[:user_id] ?
|
192
|
+
# controller.send(:user_list_url, c.params[:user_id], c.params[:id]) :
|
193
|
+
# controller.send(:list_url, c.params[:id]) }
|
194
|
+
# end
|
164
195
|
module Actions
|
165
196
|
def self.included(base) #:nodoc:
|
166
197
|
base.extend(ClassMethods)
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
end
|
172
|
-
|
173
|
-
def protected_instance_variables_with_action_caching
|
174
|
-
protected_instance_variables_without_action_caching + %w(@action_cache_path)
|
198
|
+
base.class_eval do
|
199
|
+
attr_accessor :rendered_action_cache, :action_cache_path
|
200
|
+
alias_method_chain :protected_instance_variables, :action_caching
|
201
|
+
end
|
175
202
|
end
|
176
203
|
|
177
204
|
module ClassMethods
|
@@ -179,12 +206,14 @@ module ActionController #:nodoc:
|
|
179
206
|
# See ActionController::Caching::Actions for details.
|
180
207
|
def caches_action(*actions)
|
181
208
|
return unless perform_caching
|
182
|
-
|
183
|
-
before_filter action_cache_filter
|
184
|
-
after_filter action_cache_filter
|
209
|
+
around_filter(ActionCacheFilter.new(*actions))
|
185
210
|
end
|
186
211
|
end
|
187
212
|
|
213
|
+
def protected_instance_variables_with_action_caching
|
214
|
+
protected_instance_variables_without_action_caching + %w(@action_cache_path)
|
215
|
+
end
|
216
|
+
|
188
217
|
def expire_action(options = {})
|
189
218
|
return unless perform_caching
|
190
219
|
if options[:action].is_a?(Array)
|
@@ -197,17 +226,18 @@ module ActionController #:nodoc:
|
|
197
226
|
end
|
198
227
|
|
199
228
|
class ActionCacheFilter #:nodoc:
|
200
|
-
def initialize(*actions)
|
229
|
+
def initialize(*actions, &block)
|
230
|
+
@options = actions.extract_options!
|
201
231
|
@actions = Set.new actions
|
202
232
|
end
|
203
233
|
|
204
234
|
def before(controller)
|
205
|
-
return unless @actions.include?(controller.action_name.
|
206
|
-
cache_path = ActionCachePath.new(controller,
|
235
|
+
return unless @actions.include?(controller.action_name.intern)
|
236
|
+
cache_path = ActionCachePath.new(controller, path_options_for(controller, @options))
|
207
237
|
if cache = controller.read_fragment(cache_path.path)
|
208
238
|
controller.rendered_action_cache = true
|
209
239
|
set_content_type!(controller, cache_path.extension)
|
210
|
-
controller.send(:
|
240
|
+
controller.send!(:render_for_text, cache)
|
211
241
|
false
|
212
242
|
else
|
213
243
|
controller.action_cache_path = cache_path
|
@@ -215,15 +245,22 @@ module ActionController #:nodoc:
|
|
215
245
|
end
|
216
246
|
|
217
247
|
def after(controller)
|
218
|
-
return if !@actions.include?(controller.action_name.
|
248
|
+
return if !@actions.include?(controller.action_name.intern) || controller.rendered_action_cache || !caching_allowed(controller)
|
219
249
|
controller.write_fragment(controller.action_cache_path.path, controller.response.body)
|
220
250
|
end
|
221
|
-
|
251
|
+
|
222
252
|
private
|
223
253
|
def set_content_type!(controller, extension)
|
224
|
-
controller.response.content_type = Mime::
|
254
|
+
controller.response.content_type = Mime::Type.lookup_by_extension(extension).to_s if extension
|
255
|
+
end
|
256
|
+
|
257
|
+
def path_options_for(controller, options)
|
258
|
+
((path_options = options[:cache_path]).respond_to?(:call) ? path_options.call(controller) : path_options) || {}
|
259
|
+
end
|
260
|
+
|
261
|
+
def caching_allowed(controller)
|
262
|
+
controller.request.get? && controller.response.headers['Status'].to_i == 200
|
225
263
|
end
|
226
|
-
|
227
264
|
end
|
228
265
|
|
229
266
|
class ActionCachePath
|
@@ -253,7 +290,7 @@ module ActionController #:nodoc:
|
|
253
290
|
end
|
254
291
|
|
255
292
|
def extract_extension(file_path)
|
256
|
-
# Don't want just what comes after the last '.' to
|
293
|
+
# Don't want just what comes after the last '.' to accommodate multi part extensions
|
257
294
|
# such as tar.gz.
|
258
295
|
file_path[/^[^.]+\.(.+)$/, 1]
|
259
296
|
end
|
@@ -270,25 +307,28 @@ module ActionController #:nodoc:
|
|
270
307
|
# <%= render :partial => "topic", :collection => Topic.find(:all) %>
|
271
308
|
# <% end %>
|
272
309
|
#
|
273
|
-
# This cache will bind to the name of action that called it
|
274
|
-
# <tt>expire_fragment(:controller => "topics", :action => "list")</tt
|
275
|
-
#
|
276
|
-
#
|
310
|
+
# This cache will bind to the name of the action that called it, so if this code was part of the view for the topics/list action, you would
|
311
|
+
# be able to invalidate it using <tt>expire_fragment(:controller => "topics", :action => "list")</tt>.
|
312
|
+
#
|
313
|
+
# This default behavior is of limited use if you need to cache multiple fragments per action or if the action itself is cached using
|
314
|
+
# <tt>caches_action</tt>, so we also have the option to qualify the name of the cached fragment with something like:
|
277
315
|
#
|
278
316
|
# <% cache(:action => "list", :action_suffix => "all_topics") do %>
|
279
317
|
#
|
280
|
-
# That would result in a name such as "/topics/list/all_topics",
|
281
|
-
#
|
282
|
-
#
|
283
|
-
#
|
318
|
+
# That would result in a name such as "/topics/list/all_topics", avoiding conflicts with the action cache and with any fragments that use a
|
319
|
+
# different suffix. Note that the URL doesn't have to really exist or be callable - the url_for system is just used to generate unique
|
320
|
+
# cache names that we can refer to when we need to expire the cache.
|
321
|
+
#
|
322
|
+
# The expiration call for this example is:
|
323
|
+
#
|
324
|
+
# expire_fragment(:controller => "topics", :action => "list", :action_suffix => "all_topics")
|
284
325
|
#
|
285
326
|
# == Fragment stores
|
286
327
|
#
|
287
|
-
#
|
288
|
-
# of which there are four different kinds:
|
328
|
+
# By default, cached fragments are stored in memory. The available store options are:
|
289
329
|
#
|
290
|
-
# * FileStore: Keeps the fragments on disk in the +cache_path+, which works well for all types of environments and
|
291
|
-
#
|
330
|
+
# * FileStore: Keeps the fragments on disk in the +cache_path+, which works well for all types of environments and allows all
|
331
|
+
# processes running from the same application directory to access the cached content.
|
292
332
|
# * MemoryStore: Keeps the fragments in memory, which is fine for WEBrick and for FCGI (if you don't care that each FCGI process holds its
|
293
333
|
# own fragment store). It's not suitable for CGI as the process is thrown away at the end of each request. It can potentially also take
|
294
334
|
# up a lot of memory since each process keeps all the caches in memory.
|
@@ -310,6 +350,7 @@ module ActionController #:nodoc:
|
|
310
350
|
@@fragment_cache_store = MemoryStore.new
|
311
351
|
cattr_reader :fragment_cache_store
|
312
352
|
|
353
|
+
# Defines the storage option for cached fragments
|
313
354
|
def self.fragment_cache_store=(store_option)
|
314
355
|
store, *parameters = *([ store_option ].flatten)
|
315
356
|
@@fragment_cache_store = if store.is_a?(Symbol)
|
@@ -323,6 +364,9 @@ module ActionController #:nodoc:
|
|
323
364
|
end
|
324
365
|
end
|
325
366
|
|
367
|
+
# Given a name (as described in <tt>expire_fragment</tt>), returns a key suitable for use in reading,
|
368
|
+
# writing, or expiring a cached fragment. If the name is a hash, the generated name is the return
|
369
|
+
# value of url_for on that hash (without the protocol).
|
326
370
|
def fragment_cache_key(name)
|
327
371
|
name.is_a?(Hash) ? url_for(name).split("://").last : name
|
328
372
|
end
|
@@ -331,7 +375,7 @@ module ActionController #:nodoc:
|
|
331
375
|
def cache_erb_fragment(block, name = {}, options = nil)
|
332
376
|
unless perform_caching then block.call; return end
|
333
377
|
|
334
|
-
buffer = eval(
|
378
|
+
buffer = eval(ActionView::Base.erb_variable, block.binding)
|
335
379
|
|
336
380
|
if cache = read_fragment(name, options)
|
337
381
|
buffer.concat(cache)
|
@@ -342,6 +386,7 @@ module ActionController #:nodoc:
|
|
342
386
|
end
|
343
387
|
end
|
344
388
|
|
389
|
+
# Writes <tt>content</tt> to the location signified by <tt>name</tt> (see <tt>expire_fragment</tt> for acceptable formats)
|
345
390
|
def write_fragment(name, content, options = nil)
|
346
391
|
return unless perform_caching
|
347
392
|
|
@@ -352,6 +397,7 @@ module ActionController #:nodoc:
|
|
352
397
|
content
|
353
398
|
end
|
354
399
|
|
400
|
+
# Reads a cached fragment from the location signified by <tt>name</tt> (see <tt>expire_fragment</tt> for acceptable formats)
|
355
401
|
def read_fragment(name, options = nil)
|
356
402
|
return unless perform_caching
|
357
403
|
|
@@ -368,8 +414,8 @@ module ActionController #:nodoc:
|
|
368
414
|
# %r{pages/\d*/notes}
|
369
415
|
# Ensure you do not specify start and finish in the regex (^$) because
|
370
416
|
# the actual filename matched looks like ./cache/filename/path.cache
|
371
|
-
# Regexp expiration is
|
372
|
-
# all keys
|
417
|
+
# Regexp expiration is only supported on caches that can iterate over
|
418
|
+
# all keys (unlike memcached).
|
373
419
|
def expire_fragment(name, options = nil)
|
374
420
|
return unless perform_caching
|
375
421
|
|
@@ -386,12 +432,6 @@ module ActionController #:nodoc:
|
|
386
432
|
end
|
387
433
|
end
|
388
434
|
|
389
|
-
# Deprecated -- just call expire_fragment with a regular expression
|
390
|
-
def expire_matched_fragments(matcher = /.*/, options = nil) #:nodoc:
|
391
|
-
expire_fragment(matcher, options)
|
392
|
-
end
|
393
|
-
deprecate :expire_matched_fragments => :expire_fragment
|
394
|
-
|
395
435
|
|
396
436
|
class UnthreadedMemoryStore #:nodoc:
|
397
437
|
def initialize #:nodoc:
|
@@ -438,7 +478,7 @@ module ActionController #:nodoc:
|
|
438
478
|
super
|
439
479
|
if ActionController::Base.allow_concurrency
|
440
480
|
@mutex = Mutex.new
|
441
|
-
MemoryStore.
|
481
|
+
MemoryStore.module_eval { include ThreadSafety }
|
442
482
|
end
|
443
483
|
end
|
444
484
|
end
|
@@ -453,6 +493,8 @@ module ActionController #:nodoc:
|
|
453
493
|
end
|
454
494
|
end
|
455
495
|
|
496
|
+
begin
|
497
|
+
require_library_or_gem 'memcache'
|
456
498
|
class MemCacheStore < MemoryStore #:nodoc:
|
457
499
|
attr_reader :addresses
|
458
500
|
|
@@ -464,6 +506,9 @@ module ActionController #:nodoc:
|
|
464
506
|
@data = MemCache.new(*addresses)
|
465
507
|
end
|
466
508
|
end
|
509
|
+
rescue LoadError
|
510
|
+
# MemCache wasn't available so neither can the store be
|
511
|
+
end
|
467
512
|
|
468
513
|
class UnthreadedFileStore #:nodoc:
|
469
514
|
attr_reader :cache_path
|
@@ -528,7 +573,7 @@ module ActionController #:nodoc:
|
|
528
573
|
super(cache_path)
|
529
574
|
if ActionController::Base.allow_concurrency
|
530
575
|
@mutex = Mutex.new
|
531
|
-
FileStore.
|
576
|
+
FileStore.module_eval { include ThreadSafety }
|
532
577
|
end
|
533
578
|
end
|
534
579
|
end
|
@@ -564,7 +609,7 @@ module ActionController #:nodoc:
|
|
564
609
|
module ClassMethods #:nodoc:
|
565
610
|
def cache_sweeper(*sweepers)
|
566
611
|
return unless perform_caching
|
567
|
-
configuration = sweepers.
|
612
|
+
configuration = sweepers.extract_options!
|
568
613
|
sweepers.each do |sweeper|
|
569
614
|
ActiveRecord::Base.observers << sweeper if defined?(ActiveRecord) and defined?(ActiveRecord::Base)
|
570
615
|
sweeper_instance = Object.const_get(Inflector.classify(sweeper)).instance
|
@@ -583,10 +628,6 @@ module ActionController #:nodoc:
|
|
583
628
|
class Sweeper < ActiveRecord::Observer #:nodoc:
|
584
629
|
attr_accessor :controller
|
585
630
|
|
586
|
-
# ActiveRecord::Observer will mark this class as reloadable even though it should not be.
|
587
|
-
# However, subclasses of ActionController::Caching::Sweeper should be Reloadable
|
588
|
-
include Reloadable::Deprecated
|
589
|
-
|
590
631
|
def before(controller)
|
591
632
|
self.controller = controller
|
592
633
|
callback(:before)
|
@@ -598,20 +639,45 @@ module ActionController #:nodoc:
|
|
598
639
|
self.controller = nil
|
599
640
|
end
|
600
641
|
|
642
|
+
protected
|
643
|
+
# gets the action cache path for the given options.
|
644
|
+
def action_path_for(options)
|
645
|
+
ActionController::Caching::Actions::ActionCachePath.path_for(controller, options)
|
646
|
+
end
|
647
|
+
|
648
|
+
# Retrieve instance variables set in the controller.
|
649
|
+
def assigns(key)
|
650
|
+
controller.instance_variable_get("@#{key}")
|
651
|
+
end
|
652
|
+
|
601
653
|
private
|
602
654
|
def callback(timing)
|
603
655
|
controller_callback_method_name = "#{timing}_#{controller.controller_name.underscore}"
|
604
656
|
action_callback_method_name = "#{controller_callback_method_name}_#{controller.action_name}"
|
605
657
|
|
606
|
-
send(controller_callback_method_name) if respond_to?(controller_callback_method_name)
|
607
|
-
send(action_callback_method_name) if respond_to?(action_callback_method_name)
|
658
|
+
send!(controller_callback_method_name) if respond_to?(controller_callback_method_name, true)
|
659
|
+
send!(action_callback_method_name) if respond_to?(action_callback_method_name, true)
|
608
660
|
end
|
609
661
|
|
610
662
|
def method_missing(method, *arguments)
|
611
663
|
return if @controller.nil?
|
612
|
-
@controller.send(method, *arguments)
|
664
|
+
@controller.send!(method, *arguments)
|
613
665
|
end
|
614
666
|
end
|
615
667
|
end
|
668
|
+
|
669
|
+
module SqlCache
|
670
|
+
def self.included(base) #:nodoc:
|
671
|
+
if defined?(ActiveRecord) && ActiveRecord::Base.respond_to?(:cache)
|
672
|
+
base.alias_method_chain :perform_action, :caching
|
673
|
+
end
|
674
|
+
end
|
675
|
+
|
676
|
+
def perform_action_with_caching
|
677
|
+
ActiveRecord::Base.cache do
|
678
|
+
perform_action_without_caching
|
679
|
+
end
|
680
|
+
end
|
681
|
+
end
|
616
682
|
end
|
617
683
|
end
|