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.

Files changed (200) hide show
  1. data/CHANGELOG +223 -7
  2. data/README +6 -12
  3. data/Rakefile +11 -11
  4. data/lib/action_controller.rb +9 -9
  5. data/lib/action_controller/assertions/response_assertions.rb +29 -78
  6. data/lib/action_controller/assertions/routing_assertions.rb +33 -33
  7. data/lib/action_controller/assertions/selector_assertions.rb +9 -5
  8. data/lib/action_controller/base.rb +227 -161
  9. data/lib/action_controller/benchmarking.rb +37 -24
  10. data/lib/action_controller/caching/actions.rb +53 -21
  11. data/lib/action_controller/caching/fragments.rb +10 -36
  12. data/lib/action_controller/caching/sweeping.rb +3 -3
  13. data/lib/action_controller/cgi_ext/session.rb +2 -22
  14. data/lib/action_controller/cgi_process.rb +8 -46
  15. data/lib/action_controller/components.rb +4 -1
  16. data/lib/action_controller/cookies.rb +10 -0
  17. data/lib/action_controller/dispatcher.rb +49 -15
  18. data/lib/action_controller/filters.rb +48 -10
  19. data/lib/action_controller/headers.rb +16 -14
  20. data/lib/action_controller/helpers.rb +2 -2
  21. data/lib/action_controller/http_authentication.rb +1 -1
  22. data/lib/action_controller/integration.rb +57 -60
  23. data/lib/action_controller/layout.rb +27 -53
  24. data/lib/action_controller/mime_responds.rb +5 -1
  25. data/lib/action_controller/mime_type.rb +64 -42
  26. data/lib/action_controller/mime_types.rb +2 -1
  27. data/lib/action_controller/performance_test.rb +16 -0
  28. data/lib/action_controller/polymorphic_routes.rb +16 -9
  29. data/lib/action_controller/rack_process.rb +303 -0
  30. data/lib/action_controller/request.rb +205 -97
  31. data/lib/action_controller/request_forgery_protection.rb +2 -2
  32. data/lib/action_controller/request_profiler.rb +0 -0
  33. data/lib/action_controller/rescue.rb +20 -115
  34. data/lib/action_controller/resources.rb +186 -83
  35. data/lib/action_controller/response.rb +140 -26
  36. data/lib/action_controller/routing.rb +28 -30
  37. data/lib/action_controller/routing/builder.rb +45 -54
  38. data/lib/action_controller/routing/optimisations.rb +31 -21
  39. data/lib/action_controller/routing/recognition_optimisation.rb +33 -27
  40. data/lib/action_controller/routing/route.rb +162 -147
  41. data/lib/action_controller/routing/route_set.rb +8 -7
  42. data/lib/action_controller/routing/routing_ext.rb +4 -1
  43. data/lib/action_controller/routing/segments.rb +50 -21
  44. data/lib/action_controller/session/cookie_store.rb +3 -2
  45. data/lib/action_controller/session/drb_server.rb +7 -7
  46. data/lib/action_controller/session_management.rb +6 -2
  47. data/lib/action_controller/streaming.rb +15 -8
  48. data/lib/action_controller/templates/rescues/diagnostics.erb +2 -2
  49. data/lib/action_controller/templates/rescues/template_error.erb +2 -2
  50. data/lib/action_controller/test_case.rb +66 -2
  51. data/lib/action_controller/test_process.rb +71 -66
  52. data/lib/action_controller/translation.rb +13 -0
  53. data/lib/action_controller/url_rewriter.rb +90 -13
  54. data/lib/action_controller/vendor/html-scanner/html/node.rb +9 -2
  55. data/lib/action_controller/vendor/html-scanner/html/sanitizer.rb +1 -1
  56. data/lib/action_controller/vendor/html-scanner/html/selector.rb +2 -2
  57. data/lib/action_controller/verification.rb +2 -2
  58. data/lib/action_pack/version.rb +1 -1
  59. data/lib/action_view.rb +19 -11
  60. data/lib/action_view/base.rb +184 -150
  61. data/lib/action_view/helpers.rb +38 -0
  62. data/lib/action_view/helpers/active_record_helper.rb +56 -27
  63. data/lib/action_view/helpers/asset_tag_helper.rb +356 -153
  64. data/lib/action_view/helpers/atom_feed_helper.rb +74 -19
  65. data/lib/action_view/helpers/benchmark_helper.rb +3 -3
  66. data/lib/action_view/helpers/cache_helper.rb +1 -2
  67. data/lib/action_view/helpers/capture_helper.rb +19 -44
  68. data/lib/action_view/helpers/date_helper.rb +486 -296
  69. data/lib/action_view/helpers/debug_helper.rb +20 -13
  70. data/lib/action_view/helpers/form_helper.rb +71 -30
  71. data/lib/action_view/helpers/form_options_helper.rb +15 -85
  72. data/lib/action_view/helpers/form_tag_helper.rb +61 -38
  73. data/lib/action_view/helpers/javascript_helper.rb +80 -89
  74. data/lib/action_view/helpers/number_helper.rb +179 -74
  75. data/lib/action_view/helpers/prototype_helper.rb +216 -201
  76. data/lib/action_view/helpers/record_tag_helper.rb +4 -5
  77. data/lib/action_view/helpers/sanitize_helper.rb +65 -33
  78. data/lib/action_view/helpers/scriptaculous_helper.rb +2 -2
  79. data/lib/action_view/helpers/tag_helper.rb +39 -22
  80. data/lib/action_view/helpers/text_helper.rb +212 -118
  81. data/lib/action_view/helpers/translation_helper.rb +21 -0
  82. data/lib/action_view/helpers/url_helper.rb +100 -58
  83. data/lib/action_view/inline_template.rb +13 -14
  84. data/lib/action_view/locale/en.yml +91 -0
  85. data/lib/action_view/partials.rb +100 -55
  86. data/lib/action_view/paths.rb +125 -0
  87. data/lib/action_view/renderable.rb +102 -0
  88. data/lib/action_view/renderable_partial.rb +48 -0
  89. data/lib/action_view/template.rb +90 -101
  90. data/lib/action_view/template_error.rb +11 -21
  91. data/lib/action_view/template_handler.rb +8 -28
  92. data/lib/action_view/template_handlers.rb +45 -0
  93. data/lib/action_view/template_handlers/builder.rb +5 -15
  94. data/lib/action_view/template_handlers/erb.rb +9 -6
  95. data/lib/action_view/template_handlers/rjs.rb +2 -17
  96. data/lib/action_view/test_case.rb +7 -4
  97. data/test/abstract_unit.rb +4 -1
  98. data/test/active_record_unit.rb +28 -30
  99. data/test/activerecord/render_partial_with_record_identification_test.rb +25 -12
  100. data/test/controller/action_pack_assertions_test.rb +8 -37
  101. data/test/controller/addresses_render_test.rb +0 -3
  102. data/test/controller/assert_select_test.rb +51 -24
  103. data/test/controller/base_test.rb +4 -4
  104. data/test/controller/caching_test.rb +136 -66
  105. data/test/controller/capture_test.rb +1 -21
  106. data/test/controller/cgi_test.rb +157 -10
  107. data/test/controller/components_test.rb +41 -25
  108. data/test/controller/content_type_test.rb +49 -17
  109. data/test/controller/cookie_test.rb +1 -1
  110. data/test/controller/deprecation/deprecated_base_methods_test.rb +0 -3
  111. data/test/controller/dispatcher_test.rb +9 -1
  112. data/test/controller/filter_params_test.rb +2 -2
  113. data/test/controller/filters_test.rb +13 -13
  114. data/test/controller/html-scanner/cdata_node_test.rb +15 -0
  115. data/test/controller/html-scanner/node_test.rb +21 -0
  116. data/test/controller/html-scanner/sanitizer_test.rb +14 -0
  117. data/test/controller/integration_test.rb +167 -6
  118. data/test/controller/layout_test.rb +11 -68
  119. data/test/controller/logging_test.rb +46 -0
  120. data/test/controller/mime_responds_test.rb +61 -59
  121. data/test/controller/mime_type_test.rb +6 -6
  122. data/test/controller/polymorphic_routes_test.rb +37 -2
  123. data/test/controller/rack_test.rb +323 -0
  124. data/test/controller/redirect_test.rb +72 -71
  125. data/test/controller/render_test.rb +1120 -108
  126. data/test/controller/request_forgery_protection_test.rb +66 -52
  127. data/test/controller/request_test.rb +103 -146
  128. data/test/controller/rescue_test.rb +20 -24
  129. data/test/controller/resources_test.rb +408 -25
  130. data/test/controller/routing_test.rb +1774 -1774
  131. data/test/controller/send_file_test.rb +0 -4
  132. data/test/controller/session/cookie_store_test.rb +53 -1
  133. data/test/controller/test_test.rb +15 -37
  134. data/test/controller/translation_test.rb +26 -0
  135. data/test/controller/url_rewriter_test.rb +27 -28
  136. data/test/controller/view_paths_test.rb +48 -47
  137. data/test/fixtures/_top_level_partial.html.erb +1 -0
  138. data/test/fixtures/_top_level_partial_only.erb +1 -0
  139. data/test/fixtures/developers/_developer.erb +1 -0
  140. data/test/fixtures/fun/games/_game.erb +1 -0
  141. data/test/fixtures/fun/serious/games/_game.erb +1 -0
  142. data/test/fixtures/functional_caching/formatted_fragment_cached.html.erb +3 -0
  143. data/test/fixtures/functional_caching/formatted_fragment_cached.js.rjs +6 -0
  144. data/test/fixtures/functional_caching/formatted_fragment_cached.xml.builder +5 -0
  145. data/test/fixtures/functional_caching/inline_fragment_cached.html.erb +2 -0
  146. data/test/fixtures/layouts/_column.html.erb +2 -0
  147. data/test/fixtures/projects/_project.erb +1 -0
  148. data/test/fixtures/public/javascripts/subdir/subdir.js +1 -0
  149. data/test/fixtures/public/stylesheets/subdir/subdir.css +1 -0
  150. data/test/fixtures/replies/_reply.erb +1 -0
  151. data/test/fixtures/test/_counter.html.erb +1 -0
  152. data/test/fixtures/test/_customer.erb +1 -1
  153. data/test/fixtures/test/_customer_with_var.erb +1 -0
  154. data/test/fixtures/test/_layout_for_block_with_args.html.erb +3 -0
  155. data/test/fixtures/test/_local_inspector.html.erb +1 -0
  156. data/test/fixtures/test/_partial_with_only_html_version.html.erb +1 -0
  157. data/test/fixtures/test/hello.builder +1 -1
  158. data/test/fixtures/test/hyphen-ated.erb +1 -0
  159. data/test/fixtures/test/implicit_content_type.atom.builder +2 -0
  160. data/test/fixtures/test/nested_layout.erb +3 -0
  161. data/test/fixtures/test/non_erb_block_content_for.builder +1 -1
  162. data/test/fixtures/test/sub_template_raise.html.erb +1 -0
  163. data/test/fixtures/test/template.erb +1 -0
  164. data/test/fixtures/test/using_layout_around_block_with_args.html.erb +1 -0
  165. data/test/template/active_record_helper_i18n_test.rb +46 -0
  166. data/test/template/active_record_helper_test.rb +24 -24
  167. data/test/template/asset_tag_helper_test.rb +161 -29
  168. data/test/template/atom_feed_helper_test.rb +114 -5
  169. data/test/template/compiled_templates_test.rb +59 -0
  170. data/test/template/date_helper_i18n_test.rb +113 -0
  171. data/test/template/date_helper_test.rb +403 -109
  172. data/test/template/form_helper_test.rb +213 -154
  173. data/test/template/form_options_helper_test.rb +249 -897
  174. data/test/template/form_tag_helper_test.rb +80 -32
  175. data/test/template/javascript_helper_test.rb +17 -18
  176. data/test/template/number_helper_i18n_test.rb +54 -0
  177. data/test/template/number_helper_test.rb +43 -13
  178. data/test/template/prototype_helper_test.rb +101 -84
  179. data/test/template/record_tag_helper_test.rb +24 -20
  180. data/test/template/render_test.rb +193 -0
  181. data/test/template/sanitize_helper_test.rb +3 -3
  182. data/test/template/tag_helper_test.rb +34 -14
  183. data/test/template/text_helper_test.rb +83 -9
  184. data/test/template/translation_helper_test.rb +28 -0
  185. data/test/template/url_helper_test.rb +55 -18
  186. metadata +57 -18
  187. data/lib/action_view/helpers/javascripts/controls.js +0 -963
  188. data/lib/action_view/helpers/javascripts/dragdrop.js +0 -972
  189. data/lib/action_view/helpers/javascripts/effects.js +0 -1120
  190. data/lib/action_view/helpers/javascripts/prototype.js +0 -4225
  191. data/lib/action_view/partial_template.rb +0 -70
  192. data/lib/action_view/template_finder.rb +0 -177
  193. data/lib/action_view/template_handlers/compilable.rb +0 -128
  194. data/test/controller/custom_handler_test.rb +0 -45
  195. data/test/controller/new_render_test.rb +0 -945
  196. data/test/fixtures/test/block_content_for.erb +0 -2
  197. data/test/fixtures/test/erb_content_for.erb +0 -2
  198. data/test/template/deprecated_erb_variable_test.rb +0 -9
  199. data/test/template/template_finder_test.rb +0 -73
  200. 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({:controller => 'items', :action => 'create'}, {:path => 'items', :method => :post})
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({:controller => 'items', :action => 'list', :id => '1', :view => 'print'}, 'items/list/1', { :view => "print" })
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({:controller => 'items', :action => 'index'}, 'items')
26
+ # assert_recognizes {:controller => 'items', :action => 'index'}, 'items'
27
27
  #
28
28
  # # Test a specific action
29
- # assert_recognizes({:controller => 'items', :action => 'list'}, 'items/list')
29
+ # assert_recognizes {:controller => 'items', :action => 'list'}, 'items/list'
30
30
  #
31
31
  # # Test an action with a parameter
32
- # assert_recognizes({:controller => 'items', :action => 'destroy', :id => '1'}, 'items/destroy/1')
32
+ # assert_recognizes {:controller => 'items', :action => 'destroy', :id => '1'}, 'items/destroy/1'
33
33
  #
34
34
  # # Test a custom route
35
- # assert_recognizes({:controller => 'items', :action => 'show', :id => '1'}, 'view/item1')
35
+ # assert_recognizes {:controller => 'items', :action => 'show', :id => '1'}, 'view/item1'
36
36
  #
37
37
  # # Check a Simply RESTful generated route
38
- # assert_recognizes(list_items_url, 'items/list')
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("/items", :controller => "items", :action => "index")
70
+ # assert_generates "/items", :controller => "items", :action => "index"
71
71
  #
72
72
  # # Tests that the list action is properly routed
73
- # assert_generates("/items/list", :controller => "items", :action => "list")
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("/items/list/1", { :controller => "items", :action => "list", :id => "1" })
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('/home', :controller => 'home', :action => 'index')
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('/entries/show/23', :controller => 'entries', :action => 'show', id => 23)
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('/store', { :controller => 'store', :action => 'index' }, {}, {}, 'Route for store index not generated properly')
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({ :method => 'put', :path => '/product/321' }, { :controller => "product", :action => "update", :id => "321" })
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
- # insertion operations.
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
- flunk args.shift || "No RJS statement that replaces or inserts HTML content."
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 unless monkeys is nil
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
- @@protected_view_variables = %w(@assigns @performed_redirect @performed_render @variables_added @request_origin @url @parent_controller
265
- @action_name @before_filter_chain_aborted @action_cache_path @_session @_cookies @_headers @_params
266
- @_flash @_response)
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
- # Enable or disable the collection of failure information for RoutingErrors.
281
- # This information can be extremely useful when tweaking custom routes, but is
282
- # pointless once routes have been tested and verified.
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
- unless read_inheritable_attribute(:hidden_actions)
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(&:to_s))
419
+ write_inheritable_attribute(:hidden_actions, hidden_actions | names.map { |name| name.to_s })
421
420
  end
422
421
 
423
- ## View load paths determine the bases from which template references can be made. So a call to
424
- ## render("test/template") will be looked up in the view load paths array and the closest match will be
425
- ## returned.
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
- @view_paths || superclass.view_paths
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
- # Don't render layouts for templates with the given extensions.
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
- assign_default_content_type_and_charset
526
+ send_response
527
+ ensure
528
+ process_cleanup
529
+ end
532
530
 
533
- response.request = request
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 Routes.
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, no defaults are used: <tt>url_for :controller => '/home'</tt>
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.finder.view_paths
655
+ @template.view_paths
652
656
  end
653
657
 
654
658
  def view_paths=(value)
655
- @template.finder.view_paths = value # Mutex needed
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.finder.prepend_view_path(path) # Mutex needed
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.finder.append_view_path(path) # Mutex needed
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 with status and location headers
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 render_for_file(default_template_name, nil, true)
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
- render_for_text(options[:text], options[:status])
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], options[:use_full_path], options[:locals] || {})
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], true, options[:locals] || {})
899
+ render_for_file(template, options[:status], layout, options[:locals] || {})
873
900
 
874
901
  elsif inline = options[:inline]
875
- add_variables_to_assigns
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
- template = default_template_name(action_name.to_s)
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 partial = options[:partial]
898
- partial = default_template_name if partial == true
899
- add_variables_to_assigns
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
- add_variables_to_assigns
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
- # Safari doesn't pass the headers of the return if the response is zero length
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], true)
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:// (like http://)</tt> - Is passed straight through as the target for redirection.
1020
- # * <tt>String not containing a protocol</tt> - The current protocol and host is prepended to the string.
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
- case options
1055
- when %r{^\w+://.*}
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
- redirect_to(request.protocol + request.host_with_port + options, :status=>status)
1064
-
1077
+ redirect_to_full_url(request.protocol + request.host_with_port + options, status)
1065
1078
  when :back
1066
- request.env["HTTP_REFERER"] ? redirect_to(request.env["HTTP_REFERER"], :status=>status) : raise(RedirectBackError)
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
- when Hash
1069
- redirect_to(url_for(options), :status=>status)
1070
- response.redirected_to = options
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
- else
1073
- redirect_to(url_for(options), :status=>status)
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, use_full_path = false, locals = {}) #:nodoc:
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(@template.render_file(template_path, use_full_path, locals), status)
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 = text.is_a?(Proc) ? text : text.to_s
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.extend self.class.master_helper_module
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
- logger.info "\n\nProcessing #{self.class.name}\##{action_name} (for #{request_origin}) [#{request.method.to_s.upcase}]"
1155
- logger.info " Session ID: #{@_session.session_id}" if @_session and @_session.respond_to?(:session_id)
1156
- logger.info " Parameters: #{respond_to?(:filter_parameters) ? filter_parameters(params).inspect : params.inspect}"
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 self.class.action_methods.include?(action_name)
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? && template_public?
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.content_type ||= Mime::HTML
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 ||= Set.new(public_instance_methods.map(&:to_s)) - hidden_actions
1201
- end
1202
-
1203
- def add_variables_to_assigns
1204
- unless @variables_added
1205
- add_instance_variables_to_assigns
1206
- @variables_added = true
1207
- end
1208
- end
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.finder.file_exists?(template_name)
1240
- end
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.class.controller_path}/#{action_name}"
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.class.controller_path.split('/')[-1] == path.split('/')[0]
1333
+ self.controller_path.split('/')[-1] == path.split('/')[0]
1268
1334
  end
1269
1335
 
1270
1336
  def process_cleanup