actionpack 4.0.1 → 4.2.11.1

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 (241) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +402 -1173
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +7 -7
  5. data/lib/abstract_controller/base.rb +39 -7
  6. data/lib/abstract_controller/callbacks.rb +32 -53
  7. data/lib/abstract_controller/collector.rb +11 -1
  8. data/lib/abstract_controller/helpers.rb +26 -16
  9. data/lib/abstract_controller/railties/routes_helpers.rb +3 -3
  10. data/lib/abstract_controller/rendering.rb +57 -127
  11. data/lib/abstract_controller/url_for.rb +1 -1
  12. data/lib/abstract_controller.rb +1 -2
  13. data/lib/action_controller/base.rb +19 -10
  14. data/lib/action_controller/caching/fragments.rb +7 -1
  15. data/lib/action_controller/caching.rb +2 -12
  16. data/lib/action_controller/log_subscriber.rb +29 -20
  17. data/lib/action_controller/metal/conditional_get.rb +37 -12
  18. data/lib/action_controller/metal/data_streaming.rb +1 -1
  19. data/lib/action_controller/metal/etag_with_template_digest.rb +50 -0
  20. data/lib/action_controller/metal/exceptions.rb +1 -1
  21. data/lib/action_controller/metal/flash.rb +17 -0
  22. data/lib/action_controller/metal/force_ssl.rb +2 -2
  23. data/lib/action_controller/metal/head.rb +8 -6
  24. data/lib/action_controller/metal/helpers.rb +6 -2
  25. data/lib/action_controller/metal/http_authentication.rb +45 -23
  26. data/lib/action_controller/metal/instrumentation.rb +9 -6
  27. data/lib/action_controller/metal/live.rb +173 -20
  28. data/lib/action_controller/metal/mime_responds.rb +127 -232
  29. data/lib/action_controller/metal/params_wrapper.rb +16 -9
  30. data/lib/action_controller/metal/rack_delegation.rb +1 -1
  31. data/lib/action_controller/metal/redirecting.rb +34 -26
  32. data/lib/action_controller/metal/renderers.rb +39 -12
  33. data/lib/action_controller/metal/rendering.rb +41 -14
  34. data/lib/action_controller/metal/request_forgery_protection.rb +147 -19
  35. data/lib/action_controller/metal/streaming.rb +19 -21
  36. data/lib/action_controller/metal/strong_parameters.rb +166 -22
  37. data/lib/action_controller/metal/testing.rb +0 -1
  38. data/lib/action_controller/metal/url_for.rb +11 -12
  39. data/lib/action_controller/metal.rb +14 -8
  40. data/lib/action_controller/model_naming.rb +1 -1
  41. data/lib/action_controller/railtie.rb +5 -1
  42. data/lib/action_controller/test_case.rb +160 -94
  43. data/lib/action_controller.rb +2 -18
  44. data/lib/action_dispatch/http/cache.rb +5 -4
  45. data/lib/action_dispatch/http/filter_parameters.rb +2 -2
  46. data/lib/action_dispatch/http/filter_redirect.rb +5 -4
  47. data/lib/action_dispatch/http/headers.rb +46 -10
  48. data/lib/action_dispatch/http/mime_negotiation.rb +31 -4
  49. data/lib/action_dispatch/http/mime_type.rb +25 -26
  50. data/lib/action_dispatch/http/mime_types.rb +1 -0
  51. data/lib/action_dispatch/http/parameter_filter.rb +1 -1
  52. data/lib/action_dispatch/http/parameters.rb +25 -41
  53. data/lib/action_dispatch/http/request.rb +49 -32
  54. data/lib/action_dispatch/http/response.rb +127 -25
  55. data/lib/action_dispatch/http/upload.rb +9 -21
  56. data/lib/action_dispatch/http/url.rb +97 -70
  57. data/lib/action_dispatch/journey/formatter.rb +35 -19
  58. data/lib/action_dispatch/journey/gtg/builder.rb +3 -3
  59. data/lib/action_dispatch/journey/gtg/simulator.rb +10 -7
  60. data/lib/action_dispatch/journey/gtg/transition_table.rb +23 -33
  61. data/lib/action_dispatch/journey/nfa/dot.rb +2 -2
  62. data/lib/action_dispatch/journey/nfa/simulator.rb +1 -1
  63. data/lib/action_dispatch/journey/nfa/transition_table.rb +5 -5
  64. data/lib/action_dispatch/journey/nodes/node.rb +4 -0
  65. data/lib/action_dispatch/journey/parser.rb +51 -59
  66. data/lib/action_dispatch/journey/parser.y +12 -10
  67. data/lib/action_dispatch/journey/path/pattern.rb +16 -19
  68. data/lib/action_dispatch/journey/route.rb +8 -19
  69. data/lib/action_dispatch/journey/router/strexp.rb +9 -6
  70. data/lib/action_dispatch/journey/router/utils.rb +54 -18
  71. data/lib/action_dispatch/journey/router.rb +53 -75
  72. data/lib/action_dispatch/journey/routes.rb +4 -0
  73. data/lib/action_dispatch/journey/scanner.rb +5 -5
  74. data/lib/action_dispatch/journey/visitors.rb +81 -60
  75. data/lib/action_dispatch/journey/visualizer/fsm.css +0 -4
  76. data/lib/action_dispatch/journey/visualizer/index.html.erb +2 -2
  77. data/lib/action_dispatch/middleware/callbacks.rb +7 -7
  78. data/lib/action_dispatch/middleware/cookies.rb +119 -43
  79. data/lib/action_dispatch/middleware/debug_exceptions.rb +32 -13
  80. data/lib/action_dispatch/middleware/exception_wrapper.rb +60 -20
  81. data/lib/action_dispatch/middleware/flash.rb +37 -24
  82. data/lib/action_dispatch/middleware/params_parser.rb +2 -2
  83. data/lib/action_dispatch/middleware/public_exceptions.rb +12 -3
  84. data/lib/action_dispatch/middleware/reloader.rb +11 -2
  85. data/lib/action_dispatch/middleware/remote_ip.rb +40 -54
  86. data/lib/action_dispatch/middleware/request_id.rb +1 -1
  87. data/lib/action_dispatch/middleware/session/cache_store.rb +3 -3
  88. data/lib/action_dispatch/middleware/session/cookie_store.rb +8 -7
  89. data/lib/action_dispatch/middleware/show_exceptions.rb +6 -2
  90. data/lib/action_dispatch/middleware/ssl.rb +10 -7
  91. data/lib/action_dispatch/middleware/static.rb +79 -23
  92. data/lib/action_dispatch/middleware/templates/rescues/{_request_and_response.erb → _request_and_response.html.erb} +0 -0
  93. data/lib/action_dispatch/middleware/templates/rescues/_request_and_response.text.erb +23 -0
  94. data/lib/action_dispatch/middleware/templates/rescues/_source.erb +21 -19
  95. data/lib/action_dispatch/middleware/templates/rescues/_trace.html.erb +52 -0
  96. data/lib/action_dispatch/middleware/templates/rescues/_trace.text.erb +9 -0
  97. data/lib/action_dispatch/middleware/templates/rescues/{diagnostics.erb → diagnostics.html.erb} +1 -1
  98. data/lib/action_dispatch/middleware/templates/rescues/diagnostics.text.erb +9 -0
  99. data/lib/action_dispatch/middleware/templates/rescues/layout.erb +6 -0
  100. data/lib/action_dispatch/middleware/templates/rescues/missing_template.html.erb +11 -0
  101. data/lib/action_dispatch/middleware/templates/rescues/missing_template.text.erb +3 -0
  102. data/lib/action_dispatch/middleware/templates/rescues/{routing_error.erb → routing_error.html.erb} +3 -1
  103. data/lib/action_dispatch/middleware/templates/rescues/routing_error.text.erb +11 -0
  104. data/lib/action_dispatch/middleware/templates/rescues/template_error.html.erb +20 -0
  105. data/lib/action_dispatch/middleware/templates/rescues/template_error.text.erb +7 -0
  106. data/lib/action_dispatch/middleware/templates/rescues/{unknown_action.erb → unknown_action.html.erb} +1 -1
  107. data/lib/action_dispatch/middleware/templates/rescues/unknown_action.text.erb +3 -0
  108. data/lib/action_dispatch/middleware/templates/routes/_table.html.erb +120 -64
  109. data/lib/action_dispatch/railtie.rb +5 -2
  110. data/lib/action_dispatch/request/session.rb +12 -0
  111. data/lib/action_dispatch/request/utils.rb +35 -0
  112. data/lib/action_dispatch/routing/endpoint.rb +10 -0
  113. data/lib/action_dispatch/routing/inspector.rb +11 -17
  114. data/lib/action_dispatch/routing/mapper.rb +519 -312
  115. data/lib/action_dispatch/routing/polymorphic_routes.rb +204 -79
  116. data/lib/action_dispatch/routing/redirection.rb +51 -26
  117. data/lib/action_dispatch/routing/route_set.rb +331 -206
  118. data/lib/action_dispatch/routing/routes_proxy.rb +5 -4
  119. data/lib/action_dispatch/routing/url_for.rb +19 -5
  120. data/lib/action_dispatch/routing.rb +9 -6
  121. data/lib/action_dispatch/testing/assertions/dom.rb +2 -26
  122. data/lib/action_dispatch/testing/assertions/response.rb +9 -15
  123. data/lib/action_dispatch/testing/assertions/routing.rb +22 -22
  124. data/lib/action_dispatch/testing/assertions/selector.rb +2 -429
  125. data/lib/action_dispatch/testing/assertions/tag.rb +2 -134
  126. data/lib/action_dispatch/testing/assertions.rb +11 -7
  127. data/lib/action_dispatch/testing/integration.rb +31 -29
  128. data/lib/action_dispatch/testing/test_request.rb +1 -1
  129. data/lib/action_dispatch/testing/test_response.rb +1 -5
  130. data/lib/action_dispatch.rb +5 -8
  131. data/lib/action_pack/gem_version.rb +15 -0
  132. data/lib/action_pack/version.rb +4 -7
  133. data/lib/action_pack.rb +1 -1
  134. metadata +77 -159
  135. data/lib/abstract_controller/layouts.rb +0 -423
  136. data/lib/abstract_controller/view_paths.rb +0 -96
  137. data/lib/action_controller/deprecated/integration_test.rb +0 -5
  138. data/lib/action_controller/deprecated.rb +0 -7
  139. data/lib/action_controller/metal/responder.rb +0 -287
  140. data/lib/action_controller/record_identifier.rb +0 -31
  141. data/lib/action_controller/vendor/html-scanner.rb +0 -5
  142. data/lib/action_dispatch/middleware/templates/rescues/_trace.erb +0 -24
  143. data/lib/action_dispatch/middleware/templates/rescues/missing_template.erb +0 -7
  144. data/lib/action_dispatch/middleware/templates/rescues/template_error.erb +0 -43
  145. data/lib/action_view/base.rb +0 -201
  146. data/lib/action_view/buffers.rb +0 -49
  147. data/lib/action_view/context.rb +0 -36
  148. data/lib/action_view/dependency_tracker.rb +0 -93
  149. data/lib/action_view/digestor.rb +0 -113
  150. data/lib/action_view/flows.rb +0 -76
  151. data/lib/action_view/helpers/active_model_helper.rb +0 -49
  152. data/lib/action_view/helpers/asset_tag_helper.rb +0 -320
  153. data/lib/action_view/helpers/asset_url_helper.rb +0 -355
  154. data/lib/action_view/helpers/atom_feed_helper.rb +0 -203
  155. data/lib/action_view/helpers/cache_helper.rb +0 -196
  156. data/lib/action_view/helpers/capture_helper.rb +0 -216
  157. data/lib/action_view/helpers/controller_helper.rb +0 -25
  158. data/lib/action_view/helpers/csrf_helper.rb +0 -30
  159. data/lib/action_view/helpers/date_helper.rb +0 -1083
  160. data/lib/action_view/helpers/debug_helper.rb +0 -39
  161. data/lib/action_view/helpers/form_helper.rb +0 -1880
  162. data/lib/action_view/helpers/form_options_helper.rb +0 -838
  163. data/lib/action_view/helpers/form_tag_helper.rb +0 -785
  164. data/lib/action_view/helpers/javascript_helper.rb +0 -117
  165. data/lib/action_view/helpers/number_helper.rb +0 -441
  166. data/lib/action_view/helpers/output_safety_helper.rb +0 -38
  167. data/lib/action_view/helpers/record_tag_helper.rb +0 -106
  168. data/lib/action_view/helpers/rendering_helper.rb +0 -90
  169. data/lib/action_view/helpers/sanitize_helper.rb +0 -256
  170. data/lib/action_view/helpers/tag_helper.rb +0 -173
  171. data/lib/action_view/helpers/tags/base.rb +0 -148
  172. data/lib/action_view/helpers/tags/check_box.rb +0 -64
  173. data/lib/action_view/helpers/tags/checkable.rb +0 -16
  174. data/lib/action_view/helpers/tags/collection_check_boxes.rb +0 -44
  175. data/lib/action_view/helpers/tags/collection_helpers.rb +0 -84
  176. data/lib/action_view/helpers/tags/collection_radio_buttons.rb +0 -36
  177. data/lib/action_view/helpers/tags/collection_select.rb +0 -28
  178. data/lib/action_view/helpers/tags/color_field.rb +0 -25
  179. data/lib/action_view/helpers/tags/date_field.rb +0 -13
  180. data/lib/action_view/helpers/tags/date_select.rb +0 -72
  181. data/lib/action_view/helpers/tags/datetime_field.rb +0 -22
  182. data/lib/action_view/helpers/tags/datetime_local_field.rb +0 -19
  183. data/lib/action_view/helpers/tags/datetime_select.rb +0 -8
  184. data/lib/action_view/helpers/tags/email_field.rb +0 -8
  185. data/lib/action_view/helpers/tags/file_field.rb +0 -8
  186. data/lib/action_view/helpers/tags/grouped_collection_select.rb +0 -29
  187. data/lib/action_view/helpers/tags/hidden_field.rb +0 -8
  188. data/lib/action_view/helpers/tags/label.rb +0 -66
  189. data/lib/action_view/helpers/tags/month_field.rb +0 -13
  190. data/lib/action_view/helpers/tags/number_field.rb +0 -18
  191. data/lib/action_view/helpers/tags/password_field.rb +0 -12
  192. data/lib/action_view/helpers/tags/radio_button.rb +0 -31
  193. data/lib/action_view/helpers/tags/range_field.rb +0 -8
  194. data/lib/action_view/helpers/tags/search_field.rb +0 -24
  195. data/lib/action_view/helpers/tags/select.rb +0 -40
  196. data/lib/action_view/helpers/tags/tel_field.rb +0 -8
  197. data/lib/action_view/helpers/tags/text_area.rb +0 -18
  198. data/lib/action_view/helpers/tags/text_field.rb +0 -29
  199. data/lib/action_view/helpers/tags/time_field.rb +0 -13
  200. data/lib/action_view/helpers/tags/time_select.rb +0 -8
  201. data/lib/action_view/helpers/tags/time_zone_select.rb +0 -20
  202. data/lib/action_view/helpers/tags/url_field.rb +0 -8
  203. data/lib/action_view/helpers/tags/week_field.rb +0 -13
  204. data/lib/action_view/helpers/tags.rb +0 -39
  205. data/lib/action_view/helpers/text_helper.rb +0 -443
  206. data/lib/action_view/helpers/translation_helper.rb +0 -107
  207. data/lib/action_view/helpers/url_helper.rb +0 -635
  208. data/lib/action_view/helpers.rb +0 -58
  209. data/lib/action_view/locale/en.yml +0 -56
  210. data/lib/action_view/log_subscriber.rb +0 -30
  211. data/lib/action_view/lookup_context.rb +0 -241
  212. data/lib/action_view/model_naming.rb +0 -12
  213. data/lib/action_view/path_set.rb +0 -77
  214. data/lib/action_view/railtie.rb +0 -43
  215. data/lib/action_view/record_identifier.rb +0 -84
  216. data/lib/action_view/renderer/abstract_renderer.rb +0 -47
  217. data/lib/action_view/renderer/partial_renderer.rb +0 -492
  218. data/lib/action_view/renderer/renderer.rb +0 -50
  219. data/lib/action_view/renderer/streaming_template_renderer.rb +0 -103
  220. data/lib/action_view/renderer/template_renderer.rb +0 -96
  221. data/lib/action_view/routing_url_for.rb +0 -107
  222. data/lib/action_view/tasks/dependencies.rake +0 -17
  223. data/lib/action_view/template/error.rb +0 -138
  224. data/lib/action_view/template/handlers/builder.rb +0 -26
  225. data/lib/action_view/template/handlers/erb.rb +0 -146
  226. data/lib/action_view/template/handlers/raw.rb +0 -11
  227. data/lib/action_view/template/handlers.rb +0 -53
  228. data/lib/action_view/template/resolver.rb +0 -326
  229. data/lib/action_view/template/text.rb +0 -34
  230. data/lib/action_view/template/types.rb +0 -57
  231. data/lib/action_view/template.rb +0 -339
  232. data/lib/action_view/test_case.rb +0 -270
  233. data/lib/action_view/testing/resolvers.rb +0 -50
  234. data/lib/action_view/vendor/html-scanner/html/document.rb +0 -68
  235. data/lib/action_view/vendor/html-scanner/html/node.rb +0 -532
  236. data/lib/action_view/vendor/html-scanner/html/sanitizer.rb +0 -188
  237. data/lib/action_view/vendor/html-scanner/html/selector.rb +0 -830
  238. data/lib/action_view/vendor/html-scanner/html/tokenizer.rb +0 -107
  239. data/lib/action_view/vendor/html-scanner/html/version.rb +0 -11
  240. data/lib/action_view/vendor/html-scanner.rb +0 -20
  241. data/lib/action_view.rb +0 -93
@@ -2,6 +2,9 @@ require 'rack/session/abstract/id'
2
2
  require 'active_support/core_ext/object/to_query'
3
3
  require 'active_support/core_ext/module/anonymous'
4
4
  require 'active_support/core_ext/hash/keys'
5
+ require 'active_support/deprecation'
6
+
7
+ require 'rails-dom-testing'
5
8
 
6
9
  module ActionController
7
10
  module TemplateAssertions
@@ -12,13 +15,16 @@ module ActionController
12
15
  teardown :teardown_subscriptions
13
16
  end
14
17
 
18
+ RENDER_TEMPLATE_INSTANCE_VARIABLES = %w{partials templates layouts files}.freeze
19
+
15
20
  def setup_subscriptions
16
- @_partials = Hash.new(0)
17
- @_templates = Hash.new(0)
18
- @_layouts = Hash.new(0)
19
- @_files = Hash.new(0)
21
+ RENDER_TEMPLATE_INSTANCE_VARIABLES.each do |instance_variable|
22
+ instance_variable_set("@_#{instance_variable}", Hash.new(0))
23
+ end
20
24
 
21
- ActiveSupport::Notifications.subscribe("render_template.action_view") do |_name, _start, _finish, _id, payload|
25
+ @_subscribers = []
26
+
27
+ @_subscribers << ActiveSupport::Notifications.subscribe("render_template.action_view") do |_name, _start, _finish, _id, payload|
22
28
  path = payload[:layout]
23
29
  if path
24
30
  @_layouts[path] += 1
@@ -28,42 +34,48 @@ module ActionController
28
34
  end
29
35
  end
30
36
 
31
- ActiveSupport::Notifications.subscribe("!render_template.action_view") do |_name, _start, _finish, _id, payload|
32
- path = payload[:virtual_path]
33
- next unless path
34
- partial = path =~ /^.*\/_[^\/]*$/
35
-
36
- if partial
37
- @_partials[path] += 1
38
- @_partials[path.split("/").last] += 1
39
- end
37
+ @_subscribers << ActiveSupport::Notifications.subscribe("!render_template.action_view") do |_name, _start, _finish, _id, payload|
38
+ if virtual_path = payload[:virtual_path]
39
+ partial = virtual_path =~ /^.*\/_[^\/]*$/
40
40
 
41
- @_templates[path] += 1
42
- end
43
-
44
- ActiveSupport::Notifications.subscribe("!render_template.action_view") do |_name, _start, _finish, _id, payload|
45
- next if payload[:virtual_path] # files don't have virtual path
41
+ if partial
42
+ @_partials[virtual_path] += 1
43
+ @_partials[virtual_path.split("/").last] += 1
44
+ end
46
45
 
47
- path = payload[:identifier]
48
- if path
49
- @_files[path] += 1
50
- @_files[path.split("/").last] += 1
46
+ @_templates[virtual_path] += 1
47
+ else
48
+ path = payload[:identifier]
49
+ if path
50
+ @_files[path] += 1
51
+ @_files[path.split("/").last] += 1
52
+ end
51
53
  end
52
54
  end
53
55
  end
54
56
 
55
57
  def teardown_subscriptions
56
- ActiveSupport::Notifications.unsubscribe("render_template.action_view")
57
- ActiveSupport::Notifications.unsubscribe("!render_template.action_view")
58
+ return unless defined?(@_subscribers)
59
+
60
+ @_subscribers.each do |subscriber|
61
+ ActiveSupport::Notifications.unsubscribe(subscriber)
62
+ end
58
63
  end
59
64
 
60
65
  def process(*args)
61
- @_partials = Hash.new(0)
62
- @_templates = Hash.new(0)
63
- @_layouts = Hash.new(0)
66
+ reset_template_assertion
64
67
  super
65
68
  end
66
69
 
70
+ def reset_template_assertion
71
+ RENDER_TEMPLATE_INSTANCE_VARIABLES.each do |instance_variable|
72
+ ivar_name = "@_#{instance_variable}"
73
+ if instance_variable_defined?(ivar_name)
74
+ instance_variable_get(ivar_name).clear
75
+ end
76
+ end
77
+ end
78
+
67
79
  # Asserts that the request was rendered with the appropriate template file or partials.
68
80
  #
69
81
  # # assert that the "new" view template was rendered
@@ -87,6 +99,13 @@ module ActionController
87
99
  # # assert that no partials were rendered
88
100
  # assert_template partial: false
89
101
  #
102
+ # # assert that a file was rendered
103
+ # assert_template file: "README.rdoc"
104
+ #
105
+ # # assert that no file was rendered
106
+ # assert_template file: nil
107
+ # assert_template file: false
108
+ #
90
109
  # In a view test case, you can also assert that specific locals are passed
91
110
  # to partials:
92
111
  #
@@ -136,6 +155,8 @@ module ActionController
136
155
 
137
156
  if options[:file]
138
157
  assert_includes @_files.keys, options[:file]
158
+ elsif options.key?(:file)
159
+ assert @_files.blank?, "expected no files but #{@_files.keys} was rendered"
139
160
  end
140
161
 
141
162
  if expected_partial = options[:partial]
@@ -197,7 +218,7 @@ module ActionController
197
218
  value = value.dup
198
219
  end
199
220
 
200
- if extra_keys.include?(key.to_sym)
221
+ if extra_keys.include?(key)
201
222
  non_path_parameters[key] = value
202
223
  else
203
224
  if value.is_a?(Array)
@@ -206,13 +227,16 @@ module ActionController
206
227
  value = value.to_param
207
228
  end
208
229
 
209
- path_parameters[key.to_s] = value
230
+ path_parameters[key] = value
210
231
  end
211
232
  end
212
233
 
213
234
  # Clear the combined params hash in case it was already referenced.
214
235
  @env.delete("action_dispatch.request.parameters")
215
236
 
237
+ # Clear the filter cache variables so they're not stale
238
+ @filtered_parameters = @filtered_env = @filtered_path = nil
239
+
216
240
  params = self.request_parameters.dup
217
241
  %w(controller action only_path).each do |k|
218
242
  params.delete(k)
@@ -228,7 +252,6 @@ module ActionController
228
252
  @formats = nil
229
253
  @env.delete_if { |k, v| k =~ /^(action_dispatch|rack)\.request/ }
230
254
  @env.delete_if { |k, v| k =~ /^action_dispatch\.rescue/ }
231
- @symbolized_path_params = nil
232
255
  @method = @request_method = nil
233
256
  @fullpath = @ip = @remote_ip = @protocol = nil
234
257
  @env['action_dispatch.request.query_parameters'] = {}
@@ -255,6 +278,29 @@ module ActionController
255
278
  end
256
279
  end
257
280
 
281
+ class LiveTestResponse < Live::Response
282
+ def recycle!
283
+ @body = nil
284
+ initialize
285
+ end
286
+
287
+ def body
288
+ @body ||= super
289
+ end
290
+
291
+ # Was the response successful?
292
+ alias_method :success?, :successful?
293
+
294
+ # Was the URL not found?
295
+ alias_method :missing?, :not_found?
296
+
297
+ # Were we redirected?
298
+ alias_method :redirect?, :redirection?
299
+
300
+ # Was there a server-side error?
301
+ alias_method :error?, :server_error?
302
+ end
303
+
258
304
  # Methods #destroy and #load! are overridden to avoid calling methods on the
259
305
  # @store object, which does not exist for the TestSession class.
260
306
  class TestSession < Rack::Session::Abstract::SessionHash #:nodoc:
@@ -283,6 +329,10 @@ module ActionController
283
329
  clear
284
330
  end
285
331
 
332
+ def fetch(key, *args, &block)
333
+ @data.fetch(key.to_s, *args, &block)
334
+ end
335
+
286
336
  private
287
337
 
288
338
  def load!
@@ -404,6 +454,7 @@ module ActionController
404
454
  extend ActiveSupport::Concern
405
455
  include ActionDispatch::TestProcess
406
456
  include ActiveSupport::Testing::ConstantLookup
457
+ include Rails::Dom::Testing::Assertions
407
458
 
408
459
  attr_reader :response, :request
409
460
 
@@ -427,7 +478,6 @@ module ActionController
427
478
  end
428
479
 
429
480
  def controller_class=(new_class)
430
- prepare_controller_class(new_class) if new_class
431
481
  self._controller_class = new_class
432
482
  end
433
483
 
@@ -444,11 +494,6 @@ module ActionController
444
494
  Class === constant && constant < ActionController::Metal
445
495
  end
446
496
  end
447
-
448
- def prepare_controller_class(new_class)
449
- new_class.send :include, ActionController::TestCase::RaiseActionExceptions
450
- end
451
-
452
497
  end
453
498
 
454
499
  # Simulate a GET request with the given parameters.
@@ -460,8 +505,8 @@ module ActionController
460
505
  # - +session+: A hash of parameters to store in the session. This may be +nil+.
461
506
  # - +flash+: A hash of parameters to store in the flash. This may be +nil+.
462
507
  #
463
- # You can also simulate POST, PATCH, PUT, DELETE, HEAD, and OPTIONS requests with
464
- # +post+, +patch+, +put+, +delete+, +head+, and +options+.
508
+ # You can also simulate POST, PATCH, PUT, DELETE, and HEAD requests with
509
+ # +post+, +patch+, +put+, +delete+, and +head+.
465
510
  #
466
511
  # Note that the request method is not verified. The different methods are
467
512
  # available to make the tests more expressive.
@@ -522,25 +567,50 @@ module ActionController
522
567
  end
523
568
  end
524
569
 
570
+ # Simulate a HTTP request to +action+ by specifying request method,
571
+ # parameters and set/volley the response.
572
+ #
573
+ # - +action+: The controller action to call.
574
+ # - +http_method+: Request method used to send the http request. Possible values
575
+ # are +GET+, +POST+, +PATCH+, +PUT+, +DELETE+, +HEAD+. Defaults to +GET+.
576
+ # - +parameters+: The HTTP parameters. This may be +nil+, a hash, or a
577
+ # string that is appropriately encoded (+application/x-www-form-urlencoded+
578
+ # or +multipart/form-data+).
579
+ # - +session+: A hash of parameters to store in the session. This may be +nil+.
580
+ # - +flash+: A hash of parameters to store in the flash. This may be +nil+.
581
+ #
582
+ # Example calling +create+ action and sending two params:
583
+ #
584
+ # process :create, 'POST', user: { name: 'Gaurish Sharma', email: 'user@example.com' }
585
+ #
586
+ # Example sending parameters, +nil+ session and setting a flash message:
587
+ #
588
+ # process :view, 'GET', { id: 7 }, nil, { notice: 'This is flash message' }
589
+ #
590
+ # To simulate +GET+, +POST+, +PATCH+, +PUT+, +DELETE+ and +HEAD+ requests
591
+ # prefer using #get, #post, #patch, #put, #delete and #head methods
592
+ # respectively which will make tests more expressive.
593
+ #
594
+ # Note that the request method is not verified.
525
595
  def process(action, http_method = 'GET', *args)
526
596
  check_required_ivars
527
- http_method, args = handle_old_process_api(http_method, args, caller)
528
597
 
529
598
  if args.first.is_a?(String) && http_method != 'HEAD'
530
599
  @request.env['RAW_POST_DATA'] = args.shift
531
600
  end
532
601
 
533
602
  parameters, session, flash = args
603
+ parameters ||= {}
534
604
 
535
605
  # Ensure that numbers and symbols passed as params are converted to
536
606
  # proper params, as is the case when engaging rack.
537
607
  parameters = paramify_values(parameters) if html_format?(parameters)
538
608
 
539
609
  @html_document = nil
610
+ @html_scanner_document = nil
540
611
 
541
612
  unless @controller.respond_to?(:recycle!)
542
613
  @controller.extend(Testing::Functional)
543
- @controller.class.class_eval { include Testing }
544
614
  end
545
615
 
546
616
  @request.recycle!
@@ -549,7 +619,6 @@ module ActionController
549
619
 
550
620
  @request.env['REQUEST_METHOD'] = http_method
551
621
 
552
- parameters ||= {}
553
622
  controller_class_name = @controller.class.anonymous? ?
554
623
  "anonymous" :
555
624
  @controller.class.controller_path
@@ -566,27 +635,34 @@ module ActionController
566
635
 
567
636
  name = @request.parameters[:action]
568
637
 
638
+ @controller.recycle!
569
639
  @controller.process(name)
570
640
 
571
641
  if cookies = @request.env['action_dispatch.cookies']
572
- cookies.write(@response)
642
+ unless @response.committed?
643
+ cookies.write(@response)
644
+ end
573
645
  end
574
646
  @response.prepare!
575
647
 
576
648
  @assigns = @controller.respond_to?(:view_assigns) ? @controller.view_assigns : {}
577
- @request.session['flash'] = @request.flash.to_session_value
578
- @request.session.delete('flash') if @request.session['flash'].blank?
649
+
650
+ if flash_value = @request.flash.to_session_value
651
+ @request.session['flash'] = flash_value
652
+ end
653
+
579
654
  @response
580
655
  end
581
656
 
582
657
  def setup_controller_request_and_response
583
- @request = build_request
584
- @response = build_response
585
- @response.request = @request
586
-
587
658
  @controller = nil unless defined? @controller
588
659
 
660
+ response_klass = TestResponse
661
+
589
662
  if klass = self.class.controller_class
663
+ if klass < ActionController::Live
664
+ response_klass = LiveTestResponse
665
+ end
590
666
  unless @controller
591
667
  begin
592
668
  @controller = klass.new
@@ -596,6 +672,10 @@ module ActionController
596
672
  end
597
673
  end
598
674
 
675
+ @request = build_request
676
+ @response = build_response response_klass
677
+ @response.request = @request
678
+
599
679
  if @controller
600
680
  @controller.request = @request
601
681
  @controller.params = {}
@@ -606,8 +686,8 @@ module ActionController
606
686
  TestRequest.new
607
687
  end
608
688
 
609
- def build_response
610
- TestResponse.new
689
+ def build_response(klass)
690
+ klass.new
611
691
  end
612
692
 
613
693
  included do
@@ -618,6 +698,11 @@ module ActionController
618
698
  end
619
699
 
620
700
  private
701
+
702
+ def document_root_element
703
+ html_document.root
704
+ end
705
+
621
706
  def check_required_ivars
622
707
  # Sanity check for required instance variables so we can give an
623
708
  # understandable error message.
@@ -628,27 +713,36 @@ module ActionController
628
713
  end
629
714
  end
630
715
 
631
- def handle_old_process_api(http_method, args, callstack)
632
- # 4.0: Remove this method.
633
- if http_method.is_a?(Hash)
634
- ActiveSupport::Deprecation.warn("TestCase#process now expects the HTTP method as second argument: process(action, http_method, params, session, flash)", callstack)
635
- args.unshift(http_method)
636
- http_method = args.last.is_a?(String) ? args.last : "GET"
637
- end
638
-
639
- [http_method, args]
640
- end
641
-
642
716
  def build_request_uri(action, parameters)
643
717
  unless @request.env["PATH_INFO"]
644
718
  options = @controller.respond_to?(:url_options) ? @controller.__send__(:url_options).merge(parameters) : parameters
645
719
  options.update(
646
- :only_path => true,
647
720
  :action => action,
648
721
  :relative_url_root => nil,
649
- :_recall => @request.symbolized_path_parameters)
722
+ :_recall => @request.path_parameters)
723
+
724
+ if route_name = options.delete(:use_route)
725
+ ActiveSupport::Deprecation.warn <<-MSG.squish
726
+ Passing the `use_route` option in functional tests are deprecated.
727
+ Support for this option in the `process` method (and the related
728
+ `get`, `head`, `post`, `patch`, `put` and `delete` helpers) will
729
+ be removed in the next version without replacement.
730
+
731
+ Functional tests are essentially unit tests for controllers and
732
+ they should not require knowledge to how the application's routes
733
+ are configured. Instead, you should explicitly pass the appropiate
734
+ params to the `process` method.
735
+
736
+ Previously the engines guide also contained an incorrect example
737
+ that recommended using this option to test an engine's controllers
738
+ within the dummy application. That recommendation was incorrect
739
+ and has since been corrected. Instead, you should override the
740
+ `@routes` variable in the test case with `Foo::Engine.routes`. See
741
+ the updated engines guide for details.
742
+ MSG
743
+ end
650
744
 
651
- url, query_string = @routes.url_for(options).split("?", 2)
745
+ url, query_string = @routes.path_for(options, route_name).split("?", 2)
652
746
 
653
747
  @request.env["SCRIPT_NAME"] = @controller.config.relative_url_root
654
748
  @request.env["PATH_INFO"] = url
@@ -657,39 +751,11 @@ module ActionController
657
751
  end
658
752
 
659
753
  def html_format?(parameters)
660
- return true unless parameters.is_a?(Hash)
754
+ return true unless parameters.key?(:format)
661
755
  Mime.fetch(parameters[:format]) { Mime['html'] }.html?
662
756
  end
663
757
  end
664
758
 
665
- # When the request.remote_addr remains the default for testing, which is 0.0.0.0, the exception is simply raised inline
666
- # (skipping the regular exception handling from rescue_action). If the request.remote_addr is anything else, the regular
667
- # rescue_action process takes place. This means you can test your rescue_action code by setting remote_addr to something else
668
- # than 0.0.0.0.
669
- #
670
- # The exception is stored in the exception accessor for further inspection.
671
- module RaiseActionExceptions
672
- def self.included(base) #:nodoc:
673
- unless base.method_defined?(:exception) && base.method_defined?(:exception=)
674
- base.class_eval do
675
- attr_accessor :exception
676
- protected :exception, :exception=
677
- end
678
- end
679
- end
680
-
681
- protected
682
- def rescue_action_without_handler(e)
683
- self.exception = e
684
-
685
- if request.remote_addr == "0.0.0.0"
686
- raise(e)
687
- else
688
- super(e)
689
- end
690
- end
691
- end
692
-
693
759
  include Behavior
694
760
  end
695
761
  end
@@ -17,6 +17,7 @@ module ActionController
17
17
  autoload :ConditionalGet
18
18
  autoload :Cookies
19
19
  autoload :DataStreaming
20
+ autoload :EtagWithTemplateDigest
20
21
  autoload :Flash
21
22
  autoload :ForceSSL
22
23
  autoload :Head
@@ -33,40 +34,23 @@ module ActionController
33
34
  autoload :Rendering
34
35
  autoload :RequestForgeryProtection
35
36
  autoload :Rescue
36
- autoload :Responder
37
37
  autoload :Streaming
38
38
  autoload :StrongParameters
39
39
  autoload :Testing
40
40
  autoload :UrlFor
41
41
  end
42
42
 
43
- autoload :Integration, 'action_controller/deprecated/integration_test'
44
- autoload :IntegrationTest, 'action_controller/deprecated/integration_test'
45
- autoload :Routing, 'action_controller/deprecated'
46
43
  autoload :TestCase, 'action_controller/test_case'
47
44
  autoload :TemplateAssertions, 'action_controller/test_case'
48
45
 
49
- eager_autoload do
50
- autoload :RecordIdentifier
51
- end
52
-
53
46
  def self.eager_load!
54
47
  super
55
48
  ActionController::Caching.eager_load!
56
- HTML.eager_load!
57
49
  end
58
50
  end
59
51
 
60
- # All of these simply register additional autoloads
61
- require 'action_view'
62
- require 'action_view/vendor/html-scanner'
63
-
64
- ActiveSupport.on_load(:action_view) do
65
- ActionView::RoutingUrlFor.send(:include, ActionDispatch::Routing::UrlFor)
66
- end
67
-
68
52
  # Common Active Support usage in Action Controller
69
- require 'active_support/core_ext/class/attribute_accessors'
53
+ require 'active_support/core_ext/module/attribute_accessors'
70
54
  require 'active_support/core_ext/load_error'
71
55
  require 'active_support/core_ext/module/attr_internal'
72
56
  require 'active_support/core_ext/name_error'
@@ -69,17 +69,17 @@ module ActionDispatch
69
69
  end
70
70
 
71
71
  def date
72
- if date_header = headers['Date']
72
+ if date_header = headers[DATE]
73
73
  Time.httpdate(date_header)
74
74
  end
75
75
  end
76
76
 
77
77
  def date?
78
- headers.include?('Date')
78
+ headers.include?(DATE)
79
79
  end
80
80
 
81
81
  def date=(utc_time)
82
- headers['Date'] = utc_time.httpdate
82
+ headers[DATE] = utc_time.httpdate
83
83
  end
84
84
 
85
85
  def etag=(etag)
@@ -89,10 +89,11 @@ module ActionDispatch
89
89
 
90
90
  private
91
91
 
92
+ DATE = 'Date'.freeze
92
93
  LAST_MODIFIED = "Last-Modified".freeze
93
94
  ETAG = "ETag".freeze
94
95
  CACHE_CONTROL = "Cache-Control".freeze
95
- SPECIAL_KEYS = %w[extras no-cache max-age public must-revalidate]
96
+ SPECIAL_KEYS = Set.new(%w[extras no-cache max-age public must-revalidate])
96
97
 
97
98
  def cache_control_segments
98
99
  if cache_control = self[CACHE_CONTROL]
@@ -6,8 +6,8 @@ module ActionDispatch
6
6
  module Http
7
7
  # Allows you to specify sensitive parameters which will be replaced from
8
8
  # the request log by looking in the query string of the request and all
9
- # subhashes of the params hash to filter. If a block is given, each key and
10
- # value of the params hash and all subhashes is passed to it, the value
9
+ # sub-hashes of the params hash to filter. If a block is given, each key and
10
+ # value of the params hash and all sub-hashes is passed to it, the value
11
11
  # or key can be replaced using String#replace or similar method.
12
12
  #
13
13
  # env["action_dispatch.parameter_filter"] = [:password]
@@ -5,7 +5,8 @@ module ActionDispatch
5
5
  FILTERED = '[FILTERED]'.freeze # :nodoc:
6
6
 
7
7
  def filtered_location
8
- if !location_filter.empty? && location_filter_match?
8
+ filters = location_filter
9
+ if !filters.empty? && location_filter_match?(filters)
9
10
  FILTERED
10
11
  else
11
12
  location
@@ -15,15 +16,15 @@ module ActionDispatch
15
16
  private
16
17
 
17
18
  def location_filter
18
- if request.present?
19
+ if request
19
20
  request.env['action_dispatch.redirect_filter'] || []
20
21
  else
21
22
  []
22
23
  end
23
24
  end
24
25
 
25
- def location_filter_match?
26
- location_filter.any? do |filter|
26
+ def location_filter_match?(filters)
27
+ filters.any? do |filter|
27
28
  if String === filter
28
29
  location.include?(filter)
29
30
  elsif Regexp === filter
@@ -1,34 +1,63 @@
1
1
  module ActionDispatch
2
2
  module Http
3
+ # Provides access to the request's HTTP headers from the environment.
4
+ #
5
+ # env = { "CONTENT_TYPE" => "text/plain" }
6
+ # headers = ActionDispatch::Http::Headers.new(env)
7
+ # headers["Content-Type"] # => "text/plain"
3
8
  class Headers
4
- CGI_VARIABLES = %w(
5
- CONTENT_TYPE CONTENT_LENGTH
6
- HTTPS AUTH_TYPE GATEWAY_INTERFACE
7
- PATH_INFO PATH_TRANSLATED QUERY_STRING
8
- REMOTE_ADDR REMOTE_HOST REMOTE_IDENT REMOTE_USER
9
- REQUEST_METHOD SCRIPT_NAME
10
- SERVER_NAME SERVER_PORT SERVER_PROTOCOL SERVER_SOFTWARE
11
- )
9
+ CGI_VARIABLES = Set.new(%W[
10
+ AUTH_TYPE
11
+ CONTENT_LENGTH
12
+ CONTENT_TYPE
13
+ GATEWAY_INTERFACE
14
+ HTTPS
15
+ PATH_INFO
16
+ PATH_TRANSLATED
17
+ QUERY_STRING
18
+ REMOTE_ADDR
19
+ REMOTE_HOST
20
+ REMOTE_IDENT
21
+ REMOTE_USER
22
+ REQUEST_METHOD
23
+ SCRIPT_NAME
24
+ SERVER_NAME
25
+ SERVER_PORT
26
+ SERVER_PROTOCOL
27
+ SERVER_SOFTWARE
28
+ ]).freeze
29
+
12
30
  HTTP_HEADER = /\A[A-Za-z0-9-]+\z/
13
31
 
14
32
  include Enumerable
15
33
  attr_reader :env
16
34
 
17
- def initialize(env = {})
35
+ def initialize(env = {}) # :nodoc:
18
36
  @env = env
19
37
  end
20
38
 
39
+ # Returns the value for the given key mapped to @env.
21
40
  def [](key)
22
41
  @env[env_name(key)]
23
42
  end
24
43
 
44
+ # Sets the given value for the key mapped to @env.
25
45
  def []=(key, value)
26
46
  @env[env_name(key)] = value
27
47
  end
28
48
 
29
- def key?(key); @env.key? key; end
49
+ def key?(key)
50
+ @env.key? env_name(key)
51
+ end
30
52
  alias :include? :key?
31
53
 
54
+ # Returns the value for the given key mapped to @env.
55
+ #
56
+ # If the key is not found and an optional code block is not provided,
57
+ # raises a <tt>KeyError</tt> exception.
58
+ #
59
+ # If the code block is provided, then it will be run and
60
+ # its result returned.
32
61
  def fetch(key, *args, &block)
33
62
  @env.fetch env_name(key), *args, &block
34
63
  end
@@ -37,12 +66,17 @@ module ActionDispatch
37
66
  @env.each(&block)
38
67
  end
39
68
 
69
+ # Returns a new Http::Headers instance containing the contents of
70
+ # <tt>headers_or_env</tt> and the original instance.
40
71
  def merge(headers_or_env)
41
72
  headers = Http::Headers.new(env.dup)
42
73
  headers.merge!(headers_or_env)
43
74
  headers
44
75
  end
45
76
 
77
+ # Adds the contents of <tt>headers_or_env</tt> to original instance
78
+ # entries; duplicate keys are overwritten with the values from
79
+ # <tt>headers_or_env</tt>.
46
80
  def merge!(headers_or_env)
47
81
  headers_or_env.each do |key, value|
48
82
  self[env_name(key)] = value
@@ -50,6 +84,8 @@ module ActionDispatch
50
84
  end
51
85
 
52
86
  private
87
+ # Converts a HTTP header name to an environment variable name if it is
88
+ # not contained within the headers hash.
53
89
  def env_name(key)
54
90
  key = key.to_s
55
91
  if key =~ HTTP_HEADER