actionpack 2.1.2 → 2.2.2
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 +223 -7
- data/README +6 -12
- data/Rakefile +11 -11
- data/lib/action_controller.rb +9 -9
- data/lib/action_controller/assertions/response_assertions.rb +29 -78
- data/lib/action_controller/assertions/routing_assertions.rb +33 -33
- data/lib/action_controller/assertions/selector_assertions.rb +9 -5
- data/lib/action_controller/base.rb +227 -161
- data/lib/action_controller/benchmarking.rb +37 -24
- data/lib/action_controller/caching/actions.rb +53 -21
- data/lib/action_controller/caching/fragments.rb +10 -36
- data/lib/action_controller/caching/sweeping.rb +3 -3
- data/lib/action_controller/cgi_ext/session.rb +2 -22
- data/lib/action_controller/cgi_process.rb +8 -46
- data/lib/action_controller/components.rb +4 -1
- data/lib/action_controller/cookies.rb +10 -0
- data/lib/action_controller/dispatcher.rb +49 -15
- data/lib/action_controller/filters.rb +48 -10
- data/lib/action_controller/headers.rb +16 -14
- data/lib/action_controller/helpers.rb +2 -2
- data/lib/action_controller/http_authentication.rb +1 -1
- data/lib/action_controller/integration.rb +57 -60
- data/lib/action_controller/layout.rb +27 -53
- data/lib/action_controller/mime_responds.rb +5 -1
- data/lib/action_controller/mime_type.rb +64 -42
- data/lib/action_controller/mime_types.rb +2 -1
- data/lib/action_controller/performance_test.rb +16 -0
- data/lib/action_controller/polymorphic_routes.rb +16 -9
- data/lib/action_controller/rack_process.rb +303 -0
- data/lib/action_controller/request.rb +205 -97
- data/lib/action_controller/request_forgery_protection.rb +2 -2
- data/lib/action_controller/request_profiler.rb +0 -0
- data/lib/action_controller/rescue.rb +20 -115
- data/lib/action_controller/resources.rb +186 -83
- data/lib/action_controller/response.rb +140 -26
- data/lib/action_controller/routing.rb +28 -30
- data/lib/action_controller/routing/builder.rb +45 -54
- data/lib/action_controller/routing/optimisations.rb +31 -21
- data/lib/action_controller/routing/recognition_optimisation.rb +33 -27
- data/lib/action_controller/routing/route.rb +162 -147
- data/lib/action_controller/routing/route_set.rb +8 -7
- data/lib/action_controller/routing/routing_ext.rb +4 -1
- data/lib/action_controller/routing/segments.rb +50 -21
- data/lib/action_controller/session/cookie_store.rb +3 -2
- data/lib/action_controller/session/drb_server.rb +7 -7
- data/lib/action_controller/session_management.rb +6 -2
- data/lib/action_controller/streaming.rb +15 -8
- data/lib/action_controller/templates/rescues/diagnostics.erb +2 -2
- data/lib/action_controller/templates/rescues/template_error.erb +2 -2
- data/lib/action_controller/test_case.rb +66 -2
- data/lib/action_controller/test_process.rb +71 -66
- data/lib/action_controller/translation.rb +13 -0
- data/lib/action_controller/url_rewriter.rb +90 -13
- data/lib/action_controller/vendor/html-scanner/html/node.rb +9 -2
- data/lib/action_controller/vendor/html-scanner/html/sanitizer.rb +1 -1
- data/lib/action_controller/vendor/html-scanner/html/selector.rb +2 -2
- data/lib/action_controller/verification.rb +2 -2
- data/lib/action_pack/version.rb +1 -1
- data/lib/action_view.rb +19 -11
- data/lib/action_view/base.rb +184 -150
- data/lib/action_view/helpers.rb +38 -0
- data/lib/action_view/helpers/active_record_helper.rb +56 -27
- data/lib/action_view/helpers/asset_tag_helper.rb +356 -153
- data/lib/action_view/helpers/atom_feed_helper.rb +74 -19
- data/lib/action_view/helpers/benchmark_helper.rb +3 -3
- data/lib/action_view/helpers/cache_helper.rb +1 -2
- data/lib/action_view/helpers/capture_helper.rb +19 -44
- data/lib/action_view/helpers/date_helper.rb +486 -296
- data/lib/action_view/helpers/debug_helper.rb +20 -13
- data/lib/action_view/helpers/form_helper.rb +71 -30
- data/lib/action_view/helpers/form_options_helper.rb +15 -85
- data/lib/action_view/helpers/form_tag_helper.rb +61 -38
- data/lib/action_view/helpers/javascript_helper.rb +80 -89
- data/lib/action_view/helpers/number_helper.rb +179 -74
- data/lib/action_view/helpers/prototype_helper.rb +216 -201
- data/lib/action_view/helpers/record_tag_helper.rb +4 -5
- data/lib/action_view/helpers/sanitize_helper.rb +65 -33
- data/lib/action_view/helpers/scriptaculous_helper.rb +2 -2
- data/lib/action_view/helpers/tag_helper.rb +39 -22
- data/lib/action_view/helpers/text_helper.rb +212 -118
- data/lib/action_view/helpers/translation_helper.rb +21 -0
- data/lib/action_view/helpers/url_helper.rb +100 -58
- data/lib/action_view/inline_template.rb +13 -14
- data/lib/action_view/locale/en.yml +91 -0
- data/lib/action_view/partials.rb +100 -55
- data/lib/action_view/paths.rb +125 -0
- data/lib/action_view/renderable.rb +102 -0
- data/lib/action_view/renderable_partial.rb +48 -0
- data/lib/action_view/template.rb +90 -101
- data/lib/action_view/template_error.rb +11 -21
- data/lib/action_view/template_handler.rb +8 -28
- data/lib/action_view/template_handlers.rb +45 -0
- data/lib/action_view/template_handlers/builder.rb +5 -15
- data/lib/action_view/template_handlers/erb.rb +9 -6
- data/lib/action_view/template_handlers/rjs.rb +2 -17
- data/lib/action_view/test_case.rb +7 -4
- data/test/abstract_unit.rb +4 -1
- data/test/active_record_unit.rb +28 -30
- data/test/activerecord/render_partial_with_record_identification_test.rb +25 -12
- data/test/controller/action_pack_assertions_test.rb +8 -37
- data/test/controller/addresses_render_test.rb +0 -3
- data/test/controller/assert_select_test.rb +51 -24
- data/test/controller/base_test.rb +4 -4
- data/test/controller/caching_test.rb +136 -66
- data/test/controller/capture_test.rb +1 -21
- data/test/controller/cgi_test.rb +157 -10
- data/test/controller/components_test.rb +41 -25
- data/test/controller/content_type_test.rb +49 -17
- data/test/controller/cookie_test.rb +1 -1
- data/test/controller/deprecation/deprecated_base_methods_test.rb +0 -3
- data/test/controller/dispatcher_test.rb +9 -1
- data/test/controller/filter_params_test.rb +2 -2
- data/test/controller/filters_test.rb +13 -13
- data/test/controller/html-scanner/cdata_node_test.rb +15 -0
- data/test/controller/html-scanner/node_test.rb +21 -0
- data/test/controller/html-scanner/sanitizer_test.rb +14 -0
- data/test/controller/integration_test.rb +167 -6
- data/test/controller/layout_test.rb +11 -68
- data/test/controller/logging_test.rb +46 -0
- data/test/controller/mime_responds_test.rb +61 -59
- data/test/controller/mime_type_test.rb +6 -6
- data/test/controller/polymorphic_routes_test.rb +37 -2
- data/test/controller/rack_test.rb +323 -0
- data/test/controller/redirect_test.rb +72 -71
- data/test/controller/render_test.rb +1120 -108
- data/test/controller/request_forgery_protection_test.rb +66 -52
- data/test/controller/request_test.rb +103 -146
- data/test/controller/rescue_test.rb +20 -24
- data/test/controller/resources_test.rb +408 -25
- data/test/controller/routing_test.rb +1774 -1774
- data/test/controller/send_file_test.rb +0 -4
- data/test/controller/session/cookie_store_test.rb +53 -1
- data/test/controller/test_test.rb +15 -37
- data/test/controller/translation_test.rb +26 -0
- data/test/controller/url_rewriter_test.rb +27 -28
- data/test/controller/view_paths_test.rb +48 -47
- data/test/fixtures/_top_level_partial.html.erb +1 -0
- data/test/fixtures/_top_level_partial_only.erb +1 -0
- data/test/fixtures/developers/_developer.erb +1 -0
- data/test/fixtures/fun/games/_game.erb +1 -0
- data/test/fixtures/fun/serious/games/_game.erb +1 -0
- data/test/fixtures/functional_caching/formatted_fragment_cached.html.erb +3 -0
- data/test/fixtures/functional_caching/formatted_fragment_cached.js.rjs +6 -0
- data/test/fixtures/functional_caching/formatted_fragment_cached.xml.builder +5 -0
- data/test/fixtures/functional_caching/inline_fragment_cached.html.erb +2 -0
- data/test/fixtures/layouts/_column.html.erb +2 -0
- data/test/fixtures/projects/_project.erb +1 -0
- data/test/fixtures/public/javascripts/subdir/subdir.js +1 -0
- data/test/fixtures/public/stylesheets/subdir/subdir.css +1 -0
- data/test/fixtures/replies/_reply.erb +1 -0
- data/test/fixtures/test/_counter.html.erb +1 -0
- data/test/fixtures/test/_customer.erb +1 -1
- data/test/fixtures/test/_customer_with_var.erb +1 -0
- data/test/fixtures/test/_layout_for_block_with_args.html.erb +3 -0
- data/test/fixtures/test/_local_inspector.html.erb +1 -0
- data/test/fixtures/test/_partial_with_only_html_version.html.erb +1 -0
- data/test/fixtures/test/hello.builder +1 -1
- data/test/fixtures/test/hyphen-ated.erb +1 -0
- data/test/fixtures/test/implicit_content_type.atom.builder +2 -0
- data/test/fixtures/test/nested_layout.erb +3 -0
- data/test/fixtures/test/non_erb_block_content_for.builder +1 -1
- data/test/fixtures/test/sub_template_raise.html.erb +1 -0
- data/test/fixtures/test/template.erb +1 -0
- data/test/fixtures/test/using_layout_around_block_with_args.html.erb +1 -0
- data/test/template/active_record_helper_i18n_test.rb +46 -0
- data/test/template/active_record_helper_test.rb +24 -24
- data/test/template/asset_tag_helper_test.rb +161 -29
- data/test/template/atom_feed_helper_test.rb +114 -5
- data/test/template/compiled_templates_test.rb +59 -0
- data/test/template/date_helper_i18n_test.rb +113 -0
- data/test/template/date_helper_test.rb +403 -109
- data/test/template/form_helper_test.rb +213 -154
- data/test/template/form_options_helper_test.rb +249 -897
- data/test/template/form_tag_helper_test.rb +80 -32
- data/test/template/javascript_helper_test.rb +17 -18
- data/test/template/number_helper_i18n_test.rb +54 -0
- data/test/template/number_helper_test.rb +43 -13
- data/test/template/prototype_helper_test.rb +101 -84
- data/test/template/record_tag_helper_test.rb +24 -20
- data/test/template/render_test.rb +193 -0
- data/test/template/sanitize_helper_test.rb +3 -3
- data/test/template/tag_helper_test.rb +34 -14
- data/test/template/text_helper_test.rb +83 -9
- data/test/template/translation_helper_test.rb +28 -0
- data/test/template/url_helper_test.rb +55 -18
- metadata +57 -18
- data/lib/action_view/helpers/javascripts/controls.js +0 -963
- data/lib/action_view/helpers/javascripts/dragdrop.js +0 -972
- data/lib/action_view/helpers/javascripts/effects.js +0 -1120
- data/lib/action_view/helpers/javascripts/prototype.js +0 -4225
- data/lib/action_view/partial_template.rb +0 -70
- data/lib/action_view/template_finder.rb +0 -177
- data/lib/action_view/template_handlers/compilable.rb +0 -128
- data/test/controller/custom_handler_test.rb +0 -45
- data/test/controller/new_render_test.rb +0 -945
- data/test/fixtures/test/block_content_for.erb +0 -2
- data/test/fixtures/test/erb_content_for.erb +0 -2
- data/test/template/deprecated_erb_variable_test.rb +0 -9
- data/test/template/template_finder_test.rb +0 -73
- data/test/template/template_object_test.rb +0 -95
@@ -2,7 +2,7 @@ module ActionController
|
|
2
2
|
module Assertions
|
3
3
|
# Suite of assertions to test routes generated by Rails and the handling of requests made to them.
|
4
4
|
module RoutingAssertions
|
5
|
-
# Asserts that the routing of the given +path+ was handled correctly and that the parsed options (given in the +expected_options+ hash)
|
5
|
+
# Asserts that the routing of the given +path+ was handled correctly and that the parsed options (given in the +expected_options+ hash)
|
6
6
|
# match +path+. Basically, it asserts that Rails recognizes the route given by +expected_options+.
|
7
7
|
#
|
8
8
|
# Pass a hash in the second argument (+path+) to specify the request method. This is useful for routes
|
@@ -10,32 +10,32 @@ module ActionController
|
|
10
10
|
# and a :method containing the required HTTP verb.
|
11
11
|
#
|
12
12
|
# # assert that POSTing to /items will call the create action on ItemsController
|
13
|
-
# assert_recognizes
|
13
|
+
# assert_recognizes {:controller => 'items', :action => 'create'}, {:path => 'items', :method => :post}
|
14
14
|
#
|
15
15
|
# You can also pass in +extras+ with a hash containing URL parameters that would normally be in the query string. This can be used
|
16
16
|
# to assert that values in the query string string will end up in the params hash correctly. To test query strings you must use the
|
17
|
-
# extras argument, appending the query string on the path directly will not work. For example:
|
17
|
+
# extras argument, appending the query string on the path directly will not work. For example:
|
18
18
|
#
|
19
19
|
# # assert that a path of '/items/list/1?view=print' returns the correct options
|
20
|
-
# assert_recognizes
|
20
|
+
# assert_recognizes {:controller => 'items', :action => 'list', :id => '1', :view => 'print'}, 'items/list/1', { :view => "print" }
|
21
21
|
#
|
22
|
-
# The +message+ parameter allows you to pass in an error message that is displayed upon failure.
|
22
|
+
# The +message+ parameter allows you to pass in an error message that is displayed upon failure.
|
23
23
|
#
|
24
24
|
# ==== Examples
|
25
25
|
# # Check the default route (i.e., the index action)
|
26
|
-
# assert_recognizes
|
26
|
+
# assert_recognizes {:controller => 'items', :action => 'index'}, 'items'
|
27
27
|
#
|
28
28
|
# # Test a specific action
|
29
|
-
# assert_recognizes
|
29
|
+
# assert_recognizes {:controller => 'items', :action => 'list'}, 'items/list'
|
30
30
|
#
|
31
31
|
# # Test an action with a parameter
|
32
|
-
# assert_recognizes
|
32
|
+
# assert_recognizes {:controller => 'items', :action => 'destroy', :id => '1'}, 'items/destroy/1'
|
33
33
|
#
|
34
34
|
# # Test a custom route
|
35
|
-
# assert_recognizes
|
35
|
+
# assert_recognizes {:controller => 'items', :action => 'show', :id => '1'}, 'view/item1'
|
36
36
|
#
|
37
37
|
# # Check a Simply RESTful generated route
|
38
|
-
# assert_recognizes
|
38
|
+
# assert_recognizes list_items_url, 'items/list'
|
39
39
|
def assert_recognizes(expected_options, path, extras={}, message=nil)
|
40
40
|
if path.is_a? Hash
|
41
41
|
request_method = path[:method]
|
@@ -44,16 +44,16 @@ module ActionController
|
|
44
44
|
request_method = nil
|
45
45
|
end
|
46
46
|
|
47
|
-
clean_backtrace do
|
48
|
-
ActionController::Routing::Routes.reload if ActionController::Routing::Routes.empty?
|
47
|
+
clean_backtrace do
|
48
|
+
ActionController::Routing::Routes.reload if ActionController::Routing::Routes.empty?
|
49
49
|
request = recognized_request_for(path, request_method)
|
50
|
-
|
50
|
+
|
51
51
|
expected_options = expected_options.clone
|
52
52
|
extras.each_key { |key| expected_options.delete key } unless extras.nil?
|
53
|
-
|
53
|
+
|
54
54
|
expected_options.stringify_keys!
|
55
55
|
routing_diff = expected_options.diff(request.path_parameters)
|
56
|
-
msg = build_message(message, "The recognized options <?> did not match <?>, difference: <?>",
|
56
|
+
msg = build_message(message, "The recognized options <?> did not match <?>, difference: <?>",
|
57
57
|
request.path_parameters, expected_options, expected_options.diff(request.path_parameters))
|
58
58
|
assert_block(msg) { request.path_parameters == expected_options }
|
59
59
|
end
|
@@ -64,67 +64,67 @@ module ActionController
|
|
64
64
|
# a query string. The +message+ parameter allows you to specify a custom error message for assertion failures.
|
65
65
|
#
|
66
66
|
# The +defaults+ parameter is unused.
|
67
|
-
#
|
67
|
+
#
|
68
68
|
# ==== Examples
|
69
69
|
# # Asserts that the default action is generated for a route with no action
|
70
|
-
# assert_generates
|
70
|
+
# assert_generates "/items", :controller => "items", :action => "index"
|
71
71
|
#
|
72
72
|
# # Tests that the list action is properly routed
|
73
|
-
# assert_generates
|
73
|
+
# assert_generates "/items/list", :controller => "items", :action => "list"
|
74
74
|
#
|
75
75
|
# # Tests the generation of a route with a parameter
|
76
|
-
# assert_generates
|
76
|
+
# assert_generates "/items/list/1", { :controller => "items", :action => "list", :id => "1" }
|
77
77
|
#
|
78
78
|
# # Asserts that the generated route gives us our custom route
|
79
79
|
# assert_generates "changesets/12", { :controller => 'scm', :action => 'show_diff', :revision => "12" }
|
80
80
|
def assert_generates(expected_path, options, defaults={}, extras = {}, message=nil)
|
81
|
-
clean_backtrace do
|
81
|
+
clean_backtrace do
|
82
82
|
expected_path = "/#{expected_path}" unless expected_path[0] == ?/
|
83
83
|
# Load routes.rb if it hasn't been loaded.
|
84
|
-
ActionController::Routing::Routes.reload if ActionController::Routing::Routes.empty?
|
85
|
-
|
84
|
+
ActionController::Routing::Routes.reload if ActionController::Routing::Routes.empty?
|
85
|
+
|
86
86
|
generated_path, extra_keys = ActionController::Routing::Routes.generate_extras(options, defaults)
|
87
87
|
found_extras = options.reject {|k, v| ! extra_keys.include? k}
|
88
88
|
|
89
89
|
msg = build_message(message, "found extras <?>, not <?>", found_extras, extras)
|
90
90
|
assert_block(msg) { found_extras == extras }
|
91
|
-
|
92
|
-
msg = build_message(message, "The generated path <?> did not match <?>", generated_path,
|
91
|
+
|
92
|
+
msg = build_message(message, "The generated path <?> did not match <?>", generated_path,
|
93
93
|
expected_path)
|
94
94
|
assert_block(msg) { expected_path == generated_path }
|
95
95
|
end
|
96
96
|
end
|
97
97
|
|
98
|
-
# Asserts that path and options match both ways; in other words, it verifies that <tt>path</tt> generates
|
98
|
+
# Asserts that path and options match both ways; in other words, it verifies that <tt>path</tt> generates
|
99
99
|
# <tt>options</tt> and then that <tt>options</tt> generates <tt>path</tt>. This essentially combines +assert_recognizes+
|
100
100
|
# and +assert_generates+ into one step.
|
101
101
|
#
|
102
102
|
# The +extras+ hash allows you to specify options that would normally be provided as a query string to the action. The
|
103
|
-
# +message+ parameter allows you to specify a custom error message to display upon failure.
|
103
|
+
# +message+ parameter allows you to specify a custom error message to display upon failure.
|
104
104
|
#
|
105
105
|
# ==== Examples
|
106
106
|
# # Assert a basic route: a controller with the default action (index)
|
107
|
-
# assert_routing
|
107
|
+
# assert_routing '/home', :controller => 'home', :action => 'index'
|
108
108
|
#
|
109
109
|
# # Test a route generated with a specific controller, action, and parameter (id)
|
110
|
-
# assert_routing
|
110
|
+
# assert_routing '/entries/show/23', :controller => 'entries', :action => 'show', id => 23
|
111
111
|
#
|
112
112
|
# # Assert a basic route (controller + default action), with an error message if it fails
|
113
|
-
# assert_routing
|
113
|
+
# assert_routing '/store', { :controller => 'store', :action => 'index' }, {}, {}, 'Route for store index not generated properly'
|
114
114
|
#
|
115
115
|
# # Tests a route, providing a defaults hash
|
116
116
|
# assert_routing 'controller/action/9', {:id => "9", :item => "square"}, {:controller => "controller", :action => "action"}, {}, {:item => "square"}
|
117
117
|
#
|
118
118
|
# # Tests a route with a HTTP method
|
119
|
-
# assert_routing
|
119
|
+
# assert_routing { :method => 'put', :path => '/product/321' }, { :controller => "product", :action => "update", :id => "321" }
|
120
120
|
def assert_routing(path, options, defaults={}, extras={}, message=nil)
|
121
121
|
assert_recognizes(options, path, extras, message)
|
122
|
-
|
123
|
-
controller, default_controller = options[:controller], defaults[:controller]
|
122
|
+
|
123
|
+
controller, default_controller = options[:controller], defaults[:controller]
|
124
124
|
if controller && controller.include?(?/) && default_controller && default_controller.include?(?/)
|
125
125
|
options[:controller] = "/#{controller}"
|
126
126
|
end
|
127
|
-
|
127
|
+
|
128
128
|
assert_generates(path.is_a?(Hash) ? path[:path] : path, options, defaults, extras, message)
|
129
129
|
end
|
130
130
|
|
@@ -21,10 +21,8 @@ module ActionController
|
|
21
21
|
# from the response HTML or elements selected by the enclosing assertion.
|
22
22
|
#
|
23
23
|
# In addition to HTML responses, you can make the following assertions:
|
24
|
-
# * +assert_select_rjs+ - Assertions on HTML content of RJS update and
|
25
|
-
#
|
26
|
-
# * +assert_select_encoded+ - Assertions on HTML encoded inside XML,
|
27
|
-
# for example for dealing with feed item descriptions.
|
24
|
+
# * +assert_select_rjs+ - Assertions on HTML content of RJS update and insertion operations.
|
25
|
+
# * +assert_select_encoded+ - Assertions on HTML encoded inside XML, for example for dealing with feed item descriptions.
|
28
26
|
# * +assert_select_email+ - Assertions on the HTML body of an e-mail.
|
29
27
|
#
|
30
28
|
# Also see HTML::Selector to learn how to use selectors.
|
@@ -451,7 +449,13 @@ module ActionController
|
|
451
449
|
matches
|
452
450
|
else
|
453
451
|
# RJS statement not found.
|
454
|
-
|
452
|
+
case rjs_type
|
453
|
+
when :remove, :show, :hide, :toggle
|
454
|
+
flunk_message = "No RJS statement that #{rjs_type.to_s}s '#{id}' was rendered."
|
455
|
+
else
|
456
|
+
flunk_message = "No RJS statement that replaces or inserts HTML content."
|
457
|
+
end
|
458
|
+
flunk args.shift || flunk_message
|
455
459
|
end
|
456
460
|
end
|
457
461
|
|
@@ -252,7 +252,7 @@ module ActionController #:nodoc:
|
|
252
252
|
#
|
253
253
|
# def do_something
|
254
254
|
# redirect_to(:action => "elsewhere") and return if monkeys.nil?
|
255
|
-
# render :action => "overthere" # won't be called
|
255
|
+
# render :action => "overthere" # won't be called if monkeys is nil
|
256
256
|
# end
|
257
257
|
#
|
258
258
|
class Base
|
@@ -260,10 +260,11 @@ module ActionController #:nodoc:
|
|
260
260
|
|
261
261
|
include StatusCodes
|
262
262
|
|
263
|
+
cattr_reader :protected_instance_variables
|
263
264
|
# Controller specific instance variables which will not be accessible inside views.
|
264
|
-
@@
|
265
|
-
|
266
|
-
|
265
|
+
@@protected_instance_variables = %w(@assigns @performed_redirect @performed_render @variables_added @request_origin @url @parent_controller
|
266
|
+
@action_name @before_filter_chain_aborted @action_cache_path @_session @_cookies @_headers @_params
|
267
|
+
@_flash @_response)
|
267
268
|
|
268
269
|
# Prepends all the URL-generating helpers from AssetHelper. This makes it possible to easily move javascripts, stylesheets,
|
269
270
|
# and images to a dedicated asset server away from the main web server. Example:
|
@@ -277,16 +278,9 @@ module ActionController #:nodoc:
|
|
277
278
|
@@consider_all_requests_local = true
|
278
279
|
cattr_accessor :consider_all_requests_local
|
279
280
|
|
280
|
-
#
|
281
|
-
#
|
282
|
-
#
|
283
|
-
@@debug_routes = true
|
284
|
-
cattr_accessor :debug_routes
|
285
|
-
|
286
|
-
# Indicates to Mongrel or Webrick whether to allow concurrent action
|
287
|
-
# processing. Your controller actions and any other code they call must
|
288
|
-
# also behave well when called from concurrent threads. Turned off by
|
289
|
-
# default.
|
281
|
+
# Indicates whether to allow concurrent action processing. Your
|
282
|
+
# controller actions and any other code they call must also behave well
|
283
|
+
# when called from concurrent threads. Turned off by default.
|
290
284
|
@@allow_concurrency = false
|
291
285
|
cattr_accessor :allow_concurrency
|
292
286
|
|
@@ -347,10 +341,26 @@ module ActionController #:nodoc:
|
|
347
341
|
cattr_accessor :optimise_named_routes
|
348
342
|
self.optimise_named_routes = true
|
349
343
|
|
344
|
+
# Indicates whether the response format should be determined by examining the Accept HTTP header,
|
345
|
+
# or by using the simpler params + ajax rules.
|
346
|
+
#
|
347
|
+
# If this is set to +true+ (the default) then +respond_to+ and +Request#format+ will take the Accept
|
348
|
+
# header into account. If it is set to false then the request format will be determined solely
|
349
|
+
# by examining params[:format]. If params format is missing, the format will be either HTML or
|
350
|
+
# Javascript depending on whether the request is an AJAX request.
|
351
|
+
cattr_accessor :use_accept_header
|
352
|
+
self.use_accept_header = true
|
353
|
+
|
350
354
|
# Controls whether request forgergy protection is turned on or not. Turned off by default only in test mode.
|
351
355
|
class_inheritable_accessor :allow_forgery_protection
|
352
356
|
self.allow_forgery_protection = true
|
353
357
|
|
358
|
+
# If you are deploying to a subdirectory, you will need to set
|
359
|
+
# <tt>config.action_controller.relative_url_root</tt>
|
360
|
+
# This defaults to ENV['RAILS_RELATIVE_URL_ROOT']
|
361
|
+
cattr_accessor :relative_url_root
|
362
|
+
self.relative_url_root = ENV['RAILS_RELATIVE_URL_ROOT']
|
363
|
+
|
354
364
|
# Holds the request object that's primarily used to get environment variables through access like
|
355
365
|
# <tt>request.env["REQUEST_URI"]</tt>.
|
356
366
|
attr_internal :request
|
@@ -373,16 +383,9 @@ module ActionController #:nodoc:
|
|
373
383
|
# directive. Values should always be specified as strings.
|
374
384
|
attr_internal :headers
|
375
385
|
|
376
|
-
# Holds the hash of variables that are passed on to the template class to be made available to the view. This hash
|
377
|
-
# is generated by taking a snapshot of all the instance variables in the current scope just before a template is rendered.
|
378
|
-
attr_accessor :assigns
|
379
|
-
|
380
386
|
# Returns the name of the action this controller is processing.
|
381
387
|
attr_accessor :action_name
|
382
388
|
|
383
|
-
# Templates that are exempt from layouts
|
384
|
-
@@exempt_from_layout = Set.new([/\.rjs$/])
|
385
|
-
|
386
389
|
class << self
|
387
390
|
# Factory for the standard create, process loop where the controller is discarded after processing.
|
388
391
|
def process(request, response) #:nodoc:
|
@@ -408,28 +411,27 @@ module ActionController #:nodoc:
|
|
408
411
|
# By default, all methods defined in ActionController::Base and included modules are hidden.
|
409
412
|
# More methods can be hidden using <tt>hide_actions</tt>.
|
410
413
|
def hidden_actions
|
411
|
-
|
412
|
-
write_inheritable_attribute(:hidden_actions, ActionController::Base.public_instance_methods.map(&:to_s))
|
413
|
-
end
|
414
|
-
|
415
|
-
read_inheritable_attribute(:hidden_actions)
|
414
|
+
read_inheritable_attribute(:hidden_actions) || write_inheritable_attribute(:hidden_actions, [])
|
416
415
|
end
|
417
416
|
|
418
417
|
# Hide each of the given methods from being callable as actions.
|
419
418
|
def hide_action(*names)
|
420
|
-
write_inheritable_attribute(:hidden_actions, hidden_actions | names.map
|
419
|
+
write_inheritable_attribute(:hidden_actions, hidden_actions | names.map { |name| name.to_s })
|
421
420
|
end
|
422
421
|
|
423
|
-
|
424
|
-
|
425
|
-
|
422
|
+
# View load paths determine the bases from which template references can be made. So a call to
|
423
|
+
# render("test/template") will be looked up in the view load paths array and the closest match will be
|
424
|
+
# returned.
|
426
425
|
def view_paths
|
427
|
-
|
426
|
+
if defined? @view_paths
|
427
|
+
@view_paths
|
428
|
+
else
|
429
|
+
superclass.view_paths
|
430
|
+
end
|
428
431
|
end
|
429
432
|
|
430
433
|
def view_paths=(value)
|
431
|
-
@view_paths = value
|
432
|
-
ActionView::TemplateFinder.process_view_paths(value)
|
434
|
+
@view_paths = ActionView::Base.process_view_paths(value) if value
|
433
435
|
end
|
434
436
|
|
435
437
|
# Adds a view_path to the front of the view_paths array.
|
@@ -440,9 +442,8 @@ module ActionController #:nodoc:
|
|
440
442
|
# ArticleController.prepend_view_path(["views/default", "views/custom"])
|
441
443
|
#
|
442
444
|
def prepend_view_path(path)
|
443
|
-
@view_paths = superclass.view_paths.dup if @view_paths.nil?
|
444
|
-
view_paths.unshift(*path)
|
445
|
-
ActionView::TemplateFinder.process_view_paths(path)
|
445
|
+
@view_paths = superclass.view_paths.dup if !defined?(@view_paths) || @view_paths.nil?
|
446
|
+
@view_paths.unshift(*path)
|
446
447
|
end
|
447
448
|
|
448
449
|
# Adds a view_path to the end of the view_paths array.
|
@@ -454,8 +455,7 @@ module ActionController #:nodoc:
|
|
454
455
|
#
|
455
456
|
def append_view_path(path)
|
456
457
|
@view_paths = superclass.view_paths.dup if @view_paths.nil?
|
457
|
-
view_paths.push(*path)
|
458
|
-
ActionView::TemplateFinder.process_view_paths(path)
|
458
|
+
@view_paths.push(*path)
|
459
459
|
end
|
460
460
|
|
461
461
|
# Replace sensitive parameter data from the request log.
|
@@ -507,38 +507,34 @@ module ActionController #:nodoc:
|
|
507
507
|
protected :filter_parameters
|
508
508
|
end
|
509
509
|
|
510
|
-
|
511
|
-
def exempt_from_layout(*extensions)
|
512
|
-
regexps = extensions.collect do |extension|
|
513
|
-
extension.is_a?(Regexp) ? extension : /\.#{Regexp.escape(extension.to_s)}$/
|
514
|
-
end
|
515
|
-
@@exempt_from_layout.merge regexps
|
516
|
-
end
|
510
|
+
delegate :exempt_from_layout, :to => 'ActionView::Base'
|
517
511
|
end
|
518
512
|
|
519
513
|
public
|
520
514
|
# Extracts the action_name from the request parameters and performs that action.
|
521
515
|
def process(request, response, method = :perform_action, *arguments) #:nodoc:
|
516
|
+
response.request = request
|
517
|
+
|
522
518
|
initialize_template_class(response)
|
523
519
|
assign_shortcuts(request, response)
|
524
520
|
initialize_current_url
|
525
521
|
assign_names
|
526
|
-
forget_variables_added_to_assigns
|
527
522
|
|
528
523
|
log_processing
|
529
524
|
send(method, *arguments)
|
530
525
|
|
531
|
-
|
526
|
+
send_response
|
527
|
+
ensure
|
528
|
+
process_cleanup
|
529
|
+
end
|
532
530
|
|
533
|
-
|
531
|
+
def send_response
|
534
532
|
response.prepare! unless component_request?
|
535
533
|
response
|
536
|
-
ensure
|
537
|
-
process_cleanup
|
538
534
|
end
|
539
535
|
|
540
|
-
# Returns a URL that has been rewritten according to the options hash and the defined
|
541
|
-
# (For doing a complete redirect, use redirect_to).
|
536
|
+
# Returns a URL that has been rewritten according to the options hash and the defined routes.
|
537
|
+
# (For doing a complete redirect, use +redirect_to+).
|
542
538
|
#
|
543
539
|
# <tt>url_for</tt> is used to:
|
544
540
|
#
|
@@ -578,7 +574,15 @@ module ActionController #:nodoc:
|
|
578
574
|
# missing values in the current request's parameters. Routes attempts to guess when a value should and should not be
|
579
575
|
# taken from the defaults. There are a few simple rules on how this is performed:
|
580
576
|
#
|
581
|
-
# * If the controller name begins with a slash
|
577
|
+
# * If the controller name begins with a slash no defaults are used:
|
578
|
+
#
|
579
|
+
# url_for :controller => '/home'
|
580
|
+
#
|
581
|
+
# In particular, a leading slash ensures no namespace is assumed. Thus,
|
582
|
+
# while <tt>url_for :controller => 'users'</tt> may resolve to
|
583
|
+
# <tt>Admin::UsersController</tt> if the current controller lives under
|
584
|
+
# that module, <tt>url_for :controller => '/users'</tt> ensures you link
|
585
|
+
# to <tt>::UsersController</tt> no matter what.
|
582
586
|
# * If the controller changes, the action will default to index unless provided
|
583
587
|
#
|
584
588
|
# The final rule is applied while the URL is being generated and is best illustrated by an example. Let us consider the
|
@@ -648,11 +652,11 @@ module ActionController #:nodoc:
|
|
648
652
|
|
649
653
|
# View load paths for controller.
|
650
654
|
def view_paths
|
651
|
-
@template.
|
655
|
+
@template.view_paths
|
652
656
|
end
|
653
657
|
|
654
658
|
def view_paths=(value)
|
655
|
-
@template.
|
659
|
+
@template.view_paths = ActionView::Base.process_view_paths(value)
|
656
660
|
end
|
657
661
|
|
658
662
|
# Adds a view_path to the front of the view_paths array.
|
@@ -662,7 +666,7 @@ module ActionController #:nodoc:
|
|
662
666
|
# self.prepend_view_path(["views/default", "views/custom"])
|
663
667
|
#
|
664
668
|
def prepend_view_path(path)
|
665
|
-
@template.
|
669
|
+
@template.view_paths.unshift(*path)
|
666
670
|
end
|
667
671
|
|
668
672
|
# Adds a view_path to the end of the view_paths array.
|
@@ -672,7 +676,7 @@ module ActionController #:nodoc:
|
|
672
676
|
# self.append_view_path(["views/default", "views/custom"])
|
673
677
|
#
|
674
678
|
def append_view_path(path)
|
675
|
-
@template.
|
679
|
+
@template.view_paths.push(*path)
|
676
680
|
end
|
677
681
|
|
678
682
|
protected
|
@@ -713,6 +717,9 @@ module ActionController #:nodoc:
|
|
713
717
|
# # builds the complete response.
|
714
718
|
# render :partial => "person", :collection => @winners
|
715
719
|
#
|
720
|
+
# # Renders a collection of partials but with a custom local variable name
|
721
|
+
# render :partial => "admin_person", :collection => @winners, :as => :person
|
722
|
+
#
|
716
723
|
# # Renders the same collection of partials, but also renders the
|
717
724
|
# # person_divider partial between each person partial.
|
718
725
|
# render :partial => "person", :collection => @winners, :spacer_template => "person_divider"
|
@@ -760,9 +767,6 @@ module ActionController #:nodoc:
|
|
760
767
|
# render :file => "/path/to/some/template.erb", :layout => true, :status => 404
|
761
768
|
# render :file => "c:/path/to/some/template.erb", :layout => true, :status => 404
|
762
769
|
#
|
763
|
-
# # Renders a template relative to the template root and chooses the proper file extension
|
764
|
-
# render :file => "some/template", :use_full_path => true
|
765
|
-
#
|
766
770
|
# === Rendering text
|
767
771
|
#
|
768
772
|
# Rendering of text is usually used for tests or for rendering prepared content, such as a cache. By default, text
|
@@ -788,6 +792,19 @@ module ActionController #:nodoc:
|
|
788
792
|
# # Renders "Hello from code!"
|
789
793
|
# render :text => proc { |response, output| output.write("Hello from code!") }
|
790
794
|
#
|
795
|
+
# === Rendering XML
|
796
|
+
#
|
797
|
+
# Rendering XML sets the content type to application/xml.
|
798
|
+
#
|
799
|
+
# # Renders '<name>David</name>'
|
800
|
+
# render :xml => {:name => "David"}.to_xml
|
801
|
+
#
|
802
|
+
# It's not necessary to call <tt>to_xml</tt> on the object you want to render, since <tt>render</tt> will
|
803
|
+
# automatically do that for you:
|
804
|
+
#
|
805
|
+
# # Also renders '<name>David</name>'
|
806
|
+
# render :xml => {:name => "David"}
|
807
|
+
#
|
791
808
|
# === Rendering JSON
|
792
809
|
#
|
793
810
|
# Rendering JSON sets the content type to application/json and optionally wraps the JSON in a callback. It is expected
|
@@ -833,8 +850,14 @@ module ActionController #:nodoc:
|
|
833
850
|
# page.visual_effect :highlight, 'user_list'
|
834
851
|
# end
|
835
852
|
#
|
836
|
-
# === Rendering
|
853
|
+
# === Rendering vanilla JavaScript
|
854
|
+
#
|
855
|
+
# In addition to using RJS with render :update, you can also just render vanilla JavaScript with :js.
|
837
856
|
#
|
857
|
+
# # Renders "alert('hello')" and sets the mime type to text/javascript
|
858
|
+
# render :js => "alert('hello')"
|
859
|
+
#
|
860
|
+
# === Rendering with status and location headers
|
838
861
|
# All renders take the <tt>:status</tt> and <tt>:location</tt> options and turn them into headers. They can even be used together:
|
839
862
|
#
|
840
863
|
# render :xml => post.to_xml, :status => :created, :location => post_url(post)
|
@@ -842,7 +865,7 @@ module ActionController #:nodoc:
|
|
842
865
|
raise DoubleRenderError, "Can only render or redirect once per action" if performed?
|
843
866
|
|
844
867
|
if options.nil?
|
845
|
-
return
|
868
|
+
return render(:file => default_template_name, :layout => true)
|
846
869
|
elsif !extra_options.is_a?(Hash)
|
847
870
|
raise RenderError, "You called render with invalid options : #{options.inspect}, #{extra_options.inspect}"
|
848
871
|
else
|
@@ -853,6 +876,9 @@ module ActionController #:nodoc:
|
|
853
876
|
end
|
854
877
|
end
|
855
878
|
|
879
|
+
response.layout = layout = pick_layout(options)
|
880
|
+
logger.info("Rendering template within #{layout}") if logger && layout
|
881
|
+
|
856
882
|
if content_type = options[:content_type]
|
857
883
|
response.content_type = content_type.to_s
|
858
884
|
end
|
@@ -862,68 +888,56 @@ module ActionController #:nodoc:
|
|
862
888
|
end
|
863
889
|
|
864
890
|
if options.has_key?(:text)
|
865
|
-
|
891
|
+
text = layout ? @template.render(options.merge(:text => options[:text], :layout => layout)) : options[:text]
|
892
|
+
render_for_text(text, options[:status])
|
866
893
|
|
867
894
|
else
|
868
895
|
if file = options[:file]
|
869
|
-
render_for_file(file, options[:status],
|
896
|
+
render_for_file(file, options[:status], layout, options[:locals] || {})
|
870
897
|
|
871
898
|
elsif template = options[:template]
|
872
|
-
render_for_file(template, options[:status],
|
899
|
+
render_for_file(template, options[:status], layout, options[:locals] || {})
|
873
900
|
|
874
901
|
elsif inline = options[:inline]
|
875
|
-
|
876
|
-
tmpl = ActionView::InlineTemplate.new(@template, options[:inline], options[:locals], options[:type])
|
877
|
-
render_for_text(@template.render_template(tmpl), options[:status])
|
902
|
+
render_for_text(@template.render(options.merge(:layout => layout)), options[:status])
|
878
903
|
|
879
904
|
elsif action_name = options[:action]
|
880
|
-
|
881
|
-
if options[:layout] && !template_exempt_from_layout?(template)
|
882
|
-
render_with_a_layout(:file => template, :status => options[:status], :use_full_path => true, :layout => true)
|
883
|
-
else
|
884
|
-
render_with_no_layout(:file => template, :status => options[:status], :use_full_path => true)
|
885
|
-
end
|
905
|
+
render_for_file(default_template_name(action_name.to_s), options[:status], layout)
|
886
906
|
|
887
907
|
elsif xml = options[:xml]
|
888
908
|
response.content_type ||= Mime::XML
|
889
909
|
render_for_text(xml.respond_to?(:to_xml) ? xml.to_xml : xml, options[:status])
|
890
910
|
|
911
|
+
elsif js = options[:js]
|
912
|
+
response.content_type ||= Mime::JS
|
913
|
+
render_for_text(js, options[:status])
|
914
|
+
|
891
915
|
elsif json = options[:json]
|
892
916
|
json = json.to_json unless json.is_a?(String)
|
893
917
|
json = "#{options[:callback]}(#{json})" unless options[:callback].blank?
|
894
918
|
response.content_type ||= Mime::JSON
|
895
919
|
render_for_text(json, options[:status])
|
896
920
|
|
897
|
-
elsif
|
898
|
-
partial = default_template_name if partial == true
|
899
|
-
|
900
|
-
|
901
|
-
if collection = options[:collection]
|
902
|
-
render_for_text(
|
903
|
-
@template.send!(:render_partial_collection, partial, collection,
|
904
|
-
options[:spacer_template], options[:locals]), options[:status]
|
905
|
-
)
|
921
|
+
elsif options[:partial]
|
922
|
+
options[:partial] = default_template_name if options[:partial] == true
|
923
|
+
if layout
|
924
|
+
render_for_text(@template.render(:text => @template.render(options), :layout => layout), options[:status])
|
906
925
|
else
|
907
|
-
render_for_text(
|
908
|
-
@template.send!(:render_partial, partial,
|
909
|
-
ActionView::Base::ObjectWrapper.new(options[:object]), options[:locals]), options[:status]
|
910
|
-
)
|
926
|
+
render_for_text(@template.render(options), options[:status])
|
911
927
|
end
|
912
928
|
|
913
929
|
elsif options[:update]
|
914
|
-
|
915
|
-
@template.send! :evaluate_assigns
|
930
|
+
@template.send(:_evaluate_assigns_and_ivars)
|
916
931
|
|
917
932
|
generator = ActionView::Helpers::PrototypeHelper::JavaScriptGenerator.new(@template, &block)
|
918
933
|
response.content_type = Mime::JS
|
919
934
|
render_for_text(generator.to_s, options[:status])
|
920
935
|
|
921
936
|
elsif options[:nothing]
|
922
|
-
|
923
|
-
render_for_text(" ", options[:status])
|
937
|
+
render_for_text(nil, options[:status])
|
924
938
|
|
925
939
|
else
|
926
|
-
render_for_file(default_template_name, options[:status],
|
940
|
+
render_for_file(default_template_name, options[:status], layout)
|
927
941
|
end
|
928
942
|
end
|
929
943
|
end
|
@@ -933,8 +947,8 @@ module ActionController #:nodoc:
|
|
933
947
|
def render_to_string(options = nil, &block) #:doc:
|
934
948
|
render(options, &block)
|
935
949
|
ensure
|
950
|
+
response.content_type = nil
|
936
951
|
erase_render_results
|
937
|
-
forget_variables_added_to_assigns
|
938
952
|
reset_variables_added_to_assigns
|
939
953
|
end
|
940
954
|
|
@@ -966,7 +980,6 @@ module ActionController #:nodoc:
|
|
966
980
|
render :nothing => true, :status => status
|
967
981
|
end
|
968
982
|
|
969
|
-
|
970
983
|
# Clears the rendered results, allowing for another render to be performed.
|
971
984
|
def erase_render_results #:nodoc:
|
972
985
|
response.body = nil
|
@@ -1016,10 +1029,10 @@ module ActionController #:nodoc:
|
|
1016
1029
|
#
|
1017
1030
|
# * <tt>Hash</tt> - The URL will be generated by calling url_for with the +options+.
|
1018
1031
|
# * <tt>Record</tt> - The URL will be generated by calling url_for with the +options+, which will reference a named URL for that record.
|
1019
|
-
# * <tt>String starting with protocol
|
1020
|
-
# * <tt>String not containing a protocol
|
1032
|
+
# * <tt>String</tt> starting with <tt>protocol://</tt> (like <tt>http://</tt>) - Is passed straight through as the target for redirection.
|
1033
|
+
# * <tt>String</tt> not containing a protocol - The current protocol and host is prepended to the string.
|
1021
1034
|
# * <tt>:back</tt> - Back to the page that issued the request. Useful for forms that are triggered from multiple places.
|
1022
|
-
# Short-hand for redirect_to(request.env["HTTP_REFERER"])
|
1035
|
+
# Short-hand for <tt>redirect_to(request.env["HTTP_REFERER"])</tt>
|
1023
1036
|
#
|
1024
1037
|
# Examples:
|
1025
1038
|
# redirect_to :action => "show", :id => 5
|
@@ -1051,26 +1064,76 @@ module ActionController #:nodoc:
|
|
1051
1064
|
status = 302
|
1052
1065
|
end
|
1053
1066
|
|
1054
|
-
|
1055
|
-
|
1056
|
-
raise DoubleRenderError if performed?
|
1057
|
-
logger.info("Redirected to #{options}") if logger && logger.info?
|
1058
|
-
response.redirect(options, interpret_status(status))
|
1059
|
-
response.redirected_to = options
|
1060
|
-
@performed_redirect = true
|
1067
|
+
response.redirected_to = options
|
1068
|
+
logger.info("Redirected to #{options}") if logger && logger.info?
|
1061
1069
|
|
1070
|
+
case options
|
1071
|
+
# The scheme name consist of a letter followed by any combination of
|
1072
|
+
# letters, digits, and the plus ("+"), period ("."), or hyphen ("-")
|
1073
|
+
# characters; and is terminated by a colon (":").
|
1074
|
+
when %r{^\w[\w\d+.-]*:.*}
|
1075
|
+
redirect_to_full_url(options, status)
|
1062
1076
|
when String
|
1063
|
-
|
1064
|
-
|
1077
|
+
redirect_to_full_url(request.protocol + request.host_with_port + options, status)
|
1065
1078
|
when :back
|
1066
|
-
|
1079
|
+
if referer = request.headers["Referer"]
|
1080
|
+
redirect_to(referer, :status=>status)
|
1081
|
+
else
|
1082
|
+
raise RedirectBackError
|
1083
|
+
end
|
1084
|
+
else
|
1085
|
+
redirect_to_full_url(url_for(options), status)
|
1086
|
+
end
|
1087
|
+
end
|
1067
1088
|
|
1068
|
-
|
1069
|
-
|
1070
|
-
|
1089
|
+
def redirect_to_full_url(url, status)
|
1090
|
+
raise DoubleRenderError if performed?
|
1091
|
+
response.redirect(url, interpret_status(status))
|
1092
|
+
@performed_redirect = true
|
1093
|
+
end
|
1071
1094
|
|
1072
|
-
|
1073
|
-
|
1095
|
+
# Sets the etag and/or last_modified on the response and checks it against
|
1096
|
+
# the client request. If the request doesn't match the options provided, the
|
1097
|
+
# request is considered stale and should be generated from scratch. Otherwise,
|
1098
|
+
# it's fresh and we don't need to generate anything and a reply of "304 Not Modified" is sent.
|
1099
|
+
#
|
1100
|
+
# Example:
|
1101
|
+
#
|
1102
|
+
# def show
|
1103
|
+
# @article = Article.find(params[:id])
|
1104
|
+
#
|
1105
|
+
# if stale?(:etag => @article, :last_modified => @article.created_at.utc)
|
1106
|
+
# @statistics = @article.really_expensive_call
|
1107
|
+
# respond_to do |format|
|
1108
|
+
# # all the supported formats
|
1109
|
+
# end
|
1110
|
+
# end
|
1111
|
+
# end
|
1112
|
+
def stale?(options)
|
1113
|
+
fresh_when(options)
|
1114
|
+
!request.fresh?(response)
|
1115
|
+
end
|
1116
|
+
|
1117
|
+
# Sets the etag, last_modified, or both on the response and renders a
|
1118
|
+
# "304 Not Modified" response if the request is already fresh.
|
1119
|
+
#
|
1120
|
+
# Example:
|
1121
|
+
#
|
1122
|
+
# def show
|
1123
|
+
# @article = Article.find(params[:id])
|
1124
|
+
# fresh_when(:etag => @article, :last_modified => @article.created_at.utc)
|
1125
|
+
# end
|
1126
|
+
#
|
1127
|
+
# This will render the show template if the request isn't sending a matching etag or
|
1128
|
+
# If-Modified-Since header and just a "304 Not Modified" response if there's a match.
|
1129
|
+
def fresh_when(options)
|
1130
|
+
options.assert_valid_keys(:etag, :last_modified)
|
1131
|
+
|
1132
|
+
response.etag = options[:etag] if options[:etag]
|
1133
|
+
response.last_modified = options[:last_modified] if options[:last_modified]
|
1134
|
+
|
1135
|
+
if request.fresh?(response)
|
1136
|
+
head :not_modified
|
1074
1137
|
end
|
1075
1138
|
end
|
1076
1139
|
|
@@ -1106,10 +1169,9 @@ module ActionController #:nodoc:
|
|
1106
1169
|
|
1107
1170
|
|
1108
1171
|
private
|
1109
|
-
def render_for_file(template_path, status = nil,
|
1110
|
-
add_variables_to_assigns
|
1172
|
+
def render_for_file(template_path, status = nil, layout = nil, locals = {}) #:nodoc:
|
1111
1173
|
logger.info("Rendering #{template_path}" + (status ? " (#{status})" : '')) if logger
|
1112
|
-
render_for_text
|
1174
|
+
render_for_text @template.render(:file => template_path, :locals => locals, :layout => layout), status
|
1113
1175
|
end
|
1114
1176
|
|
1115
1177
|
def render_for_text(text = nil, status = nil, append_response = false) #:nodoc:
|
@@ -1121,13 +1183,17 @@ module ActionController #:nodoc:
|
|
1121
1183
|
response.body ||= ''
|
1122
1184
|
response.body << text.to_s
|
1123
1185
|
else
|
1124
|
-
response.body =
|
1186
|
+
response.body = case text
|
1187
|
+
when Proc then text
|
1188
|
+
when nil then " " # Safari doesn't pass the headers of the return if the response is zero length
|
1189
|
+
else text.to_s
|
1190
|
+
end
|
1125
1191
|
end
|
1126
1192
|
end
|
1127
1193
|
|
1128
1194
|
def initialize_template_class(response)
|
1129
1195
|
response.template = ActionView::Base.new(self.class.view_paths, {}, self)
|
1130
|
-
response.template.
|
1196
|
+
response.template.helpers.send :include, self.class.master_helper_module
|
1131
1197
|
response.redirected_to = nil
|
1132
1198
|
@performed_render = @performed_redirect = false
|
1133
1199
|
end
|
@@ -1140,7 +1206,6 @@ module ActionController #:nodoc:
|
|
1140
1206
|
|
1141
1207
|
@_session = @_response.session
|
1142
1208
|
@template = @_response.template
|
1143
|
-
@assigns = @_response.template.assigns
|
1144
1209
|
|
1145
1210
|
@_headers = @_response.headers
|
1146
1211
|
end
|
@@ -1151,27 +1216,49 @@ module ActionController #:nodoc:
|
|
1151
1216
|
|
1152
1217
|
def log_processing
|
1153
1218
|
if logger && logger.info?
|
1154
|
-
|
1155
|
-
|
1156
|
-
|
1219
|
+
log_processing_for_request_id
|
1220
|
+
log_processing_for_session_id
|
1221
|
+
log_processing_for_parameters
|
1157
1222
|
end
|
1158
1223
|
end
|
1224
|
+
|
1225
|
+
def log_processing_for_request_id
|
1226
|
+
request_id = "\n\nProcessing #{self.class.name}\##{action_name} "
|
1227
|
+
request_id << "to #{params[:format]} " if params[:format]
|
1228
|
+
request_id << "(for #{request_origin}) [#{request.method.to_s.upcase}]"
|
1229
|
+
|
1230
|
+
logger.info(request_id)
|
1231
|
+
end
|
1232
|
+
|
1233
|
+
def log_processing_for_session_id
|
1234
|
+
if @_session && @_session.respond_to?(:session_id) && @_session.respond_to?(:dbman) &&
|
1235
|
+
!@_session.dbman.is_a?(CGI::Session::CookieStore)
|
1236
|
+
logger.info " Session ID: #{@_session.session_id}"
|
1237
|
+
end
|
1238
|
+
end
|
1239
|
+
|
1240
|
+
def log_processing_for_parameters
|
1241
|
+
parameters = respond_to?(:filter_parameters) ? filter_parameters(params) : params.dup
|
1242
|
+
parameters = parameters.except!(:controller, :action, :format, :_method)
|
1243
|
+
|
1244
|
+
logger.info " Parameters: #{parameters.inspect}" unless parameters.empty?
|
1245
|
+
end
|
1159
1246
|
|
1160
1247
|
def default_render #:nodoc:
|
1161
1248
|
render
|
1162
1249
|
end
|
1163
1250
|
|
1164
1251
|
def perform_action
|
1165
|
-
if
|
1252
|
+
if action_methods.include?(action_name)
|
1166
1253
|
send(action_name)
|
1167
1254
|
default_render unless performed?
|
1168
1255
|
elsif respond_to? :method_missing
|
1169
1256
|
method_missing action_name
|
1170
1257
|
default_render unless performed?
|
1171
|
-
elsif template_exists?
|
1258
|
+
elsif template_exists?
|
1172
1259
|
default_render
|
1173
1260
|
else
|
1174
|
-
raise UnknownAction, "No action responded to #{action_name}", caller
|
1261
|
+
raise UnknownAction, "No action responded to #{action_name}. Actions: #{action_methods.sort.to_sentence}", caller
|
1175
1262
|
end
|
1176
1263
|
end
|
1177
1264
|
|
@@ -1184,43 +1271,30 @@ module ActionController #:nodoc:
|
|
1184
1271
|
end
|
1185
1272
|
|
1186
1273
|
def assign_default_content_type_and_charset
|
1187
|
-
response.
|
1188
|
-
response.charset ||= self.class.default_charset unless sending_file?
|
1189
|
-
end
|
1190
|
-
|
1191
|
-
def sending_file?
|
1192
|
-
response.headers["Content-Transfer-Encoding"] == "binary"
|
1274
|
+
response.assign_default_content_type_and_charset!
|
1193
1275
|
end
|
1276
|
+
deprecate :assign_default_content_type_and_charset => :'response.assign_default_content_type_and_charset!'
|
1194
1277
|
|
1195
1278
|
def action_methods
|
1196
1279
|
self.class.action_methods
|
1197
1280
|
end
|
1198
1281
|
|
1199
1282
|
def self.action_methods
|
1200
|
-
@action_methods ||=
|
1201
|
-
|
1202
|
-
|
1203
|
-
|
1204
|
-
|
1205
|
-
|
1206
|
-
|
1207
|
-
|
1208
|
-
|
1209
|
-
|
1210
|
-
def forget_variables_added_to_assigns
|
1211
|
-
@variables_added = nil
|
1283
|
+
@action_methods ||=
|
1284
|
+
# All public instance methods of this class, including ancestors
|
1285
|
+
public_instance_methods(true).map { |m| m.to_s }.to_set -
|
1286
|
+
# Except for public instance methods of Base and its ancestors
|
1287
|
+
Base.public_instance_methods(true).map { |m| m.to_s } +
|
1288
|
+
# Be sure to include shadowed public instance methods of this class
|
1289
|
+
public_instance_methods(false).map { |m| m.to_s } -
|
1290
|
+
# And always exclude explicitly hidden actions
|
1291
|
+
hidden_actions
|
1212
1292
|
end
|
1213
1293
|
|
1214
1294
|
def reset_variables_added_to_assigns
|
1215
1295
|
@template.instance_variable_set("@assigns_added", nil)
|
1216
1296
|
end
|
1217
1297
|
|
1218
|
-
def add_instance_variables_to_assigns
|
1219
|
-
(instance_variable_names - @@protected_view_variables).each do |var|
|
1220
|
-
@assigns[var[1..-1]] = instance_variable_get(var)
|
1221
|
-
end
|
1222
|
-
end
|
1223
|
-
|
1224
1298
|
def request_origin
|
1225
1299
|
# this *needs* to be cached!
|
1226
1300
|
# otherwise you'd get different results if calling it more than once
|
@@ -1236,17 +1310,9 @@ module ActionController #:nodoc:
|
|
1236
1310
|
end
|
1237
1311
|
|
1238
1312
|
def template_exists?(template_name = default_template_name)
|
1239
|
-
@template.
|
1240
|
-
|
1241
|
-
|
1242
|
-
def template_public?(template_name = default_template_name)
|
1243
|
-
@template.file_public?(template_name)
|
1244
|
-
end
|
1245
|
-
|
1246
|
-
def template_exempt_from_layout?(template_name = default_template_name)
|
1247
|
-
extension = @template && @template.finder.pick_template_extension(template_name)
|
1248
|
-
name_with_extension = !template_name.include?('.') && extension ? "#{template_name}.#{extension}" : template_name
|
1249
|
-
@@exempt_from_layout.any? { |ext| name_with_extension =~ ext }
|
1313
|
+
@template.send(:_pick_template, template_name) ? true : false
|
1314
|
+
rescue ActionView::MissingTemplate
|
1315
|
+
false
|
1250
1316
|
end
|
1251
1317
|
|
1252
1318
|
def default_template_name(action_name = self.action_name)
|
@@ -1256,7 +1322,7 @@ module ActionController #:nodoc:
|
|
1256
1322
|
action_name = strip_out_controller(action_name)
|
1257
1323
|
end
|
1258
1324
|
end
|
1259
|
-
"#{self.
|
1325
|
+
"#{self.controller_path}/#{action_name}"
|
1260
1326
|
end
|
1261
1327
|
|
1262
1328
|
def strip_out_controller(path)
|
@@ -1264,7 +1330,7 @@ module ActionController #:nodoc:
|
|
1264
1330
|
end
|
1265
1331
|
|
1266
1332
|
def template_path_includes_controller?(path)
|
1267
|
-
self.
|
1333
|
+
self.controller_path.split('/')[-1] == path.split('/')[0]
|
1268
1334
|
end
|
1269
1335
|
|
1270
1336
|
def process_cleanup
|