actionpack 3.2.22.5 → 4.0.0.beta1

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 (265) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +641 -418
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +5 -288
  5. data/lib/abstract_controller.rb +1 -8
  6. data/lib/abstract_controller/asset_paths.rb +2 -2
  7. data/lib/abstract_controller/base.rb +39 -37
  8. data/lib/abstract_controller/callbacks.rb +101 -82
  9. data/lib/abstract_controller/collector.rb +7 -3
  10. data/lib/abstract_controller/helpers.rb +23 -11
  11. data/lib/abstract_controller/layouts.rb +68 -73
  12. data/lib/abstract_controller/logger.rb +1 -2
  13. data/lib/abstract_controller/rendering.rb +22 -13
  14. data/lib/abstract_controller/translation.rb +16 -1
  15. data/lib/abstract_controller/url_for.rb +6 -6
  16. data/lib/abstract_controller/view_paths.rb +1 -1
  17. data/lib/action_controller.rb +15 -6
  18. data/lib/action_controller/base.rb +46 -22
  19. data/lib/action_controller/caching.rb +46 -33
  20. data/lib/action_controller/caching/fragments.rb +23 -53
  21. data/lib/action_controller/deprecated.rb +5 -1
  22. data/lib/action_controller/deprecated/integration_test.rb +3 -0
  23. data/lib/action_controller/log_subscriber.rb +11 -8
  24. data/lib/action_controller/metal.rb +16 -30
  25. data/lib/action_controller/metal/conditional_get.rb +76 -32
  26. data/lib/action_controller/metal/data_streaming.rb +20 -26
  27. data/lib/action_controller/metal/exceptions.rb +19 -6
  28. data/lib/action_controller/metal/flash.rb +24 -9
  29. data/lib/action_controller/metal/force_ssl.rb +32 -9
  30. data/lib/action_controller/metal/head.rb +25 -4
  31. data/lib/action_controller/metal/helpers.rb +6 -9
  32. data/lib/action_controller/metal/hide_actions.rb +1 -2
  33. data/lib/action_controller/metal/http_authentication.rb +105 -87
  34. data/lib/action_controller/metal/implicit_render.rb +1 -1
  35. data/lib/action_controller/metal/instrumentation.rb +2 -1
  36. data/lib/action_controller/metal/live.rb +141 -0
  37. data/lib/action_controller/metal/mime_responds.rb +161 -47
  38. data/lib/action_controller/metal/params_wrapper.rb +112 -74
  39. data/lib/action_controller/metal/rack_delegation.rb +9 -3
  40. data/lib/action_controller/metal/redirecting.rb +15 -20
  41. data/lib/action_controller/metal/renderers.rb +11 -9
  42. data/lib/action_controller/metal/rendering.rb +8 -0
  43. data/lib/action_controller/metal/request_forgery_protection.rb +112 -19
  44. data/lib/action_controller/metal/responder.rb +20 -19
  45. data/lib/action_controller/metal/streaming.rb +12 -18
  46. data/lib/action_controller/metal/strong_parameters.rb +516 -0
  47. data/lib/action_controller/metal/testing.rb +13 -18
  48. data/lib/action_controller/metal/url_for.rb +27 -25
  49. data/lib/action_controller/model_naming.rb +12 -0
  50. data/lib/action_controller/railtie.rb +33 -17
  51. data/lib/action_controller/railties/helpers.rb +22 -0
  52. data/lib/action_controller/record_identifier.rb +18 -72
  53. data/lib/action_controller/test_case.rb +215 -123
  54. data/lib/action_controller/vendor/html-scanner.rb +4 -19
  55. data/lib/action_dispatch.rb +27 -19
  56. data/lib/action_dispatch/http/cache.rb +63 -11
  57. data/lib/action_dispatch/http/filter_parameters.rb +18 -8
  58. data/lib/action_dispatch/http/filter_redirect.rb +37 -0
  59. data/lib/action_dispatch/http/headers.rb +27 -19
  60. data/lib/action_dispatch/http/mime_negotiation.rb +25 -2
  61. data/lib/action_dispatch/http/mime_type.rb +145 -113
  62. data/lib/action_dispatch/http/mime_types.rb +1 -1
  63. data/lib/action_dispatch/http/parameter_filter.rb +44 -46
  64. data/lib/action_dispatch/http/parameters.rb +12 -5
  65. data/lib/action_dispatch/http/rack_cache.rb +2 -3
  66. data/lib/action_dispatch/http/request.rb +49 -18
  67. data/lib/action_dispatch/http/response.rb +129 -35
  68. data/lib/action_dispatch/http/upload.rb +60 -17
  69. data/lib/action_dispatch/http/url.rb +53 -31
  70. data/lib/action_dispatch/journey.rb +5 -0
  71. data/lib/action_dispatch/journey/backwards.rb +5 -0
  72. data/lib/action_dispatch/journey/formatter.rb +146 -0
  73. data/lib/action_dispatch/journey/gtg/builder.rb +162 -0
  74. data/lib/action_dispatch/journey/gtg/simulator.rb +44 -0
  75. data/lib/action_dispatch/journey/gtg/transition_table.rb +156 -0
  76. data/lib/action_dispatch/journey/nfa/builder.rb +76 -0
  77. data/lib/action_dispatch/journey/nfa/dot.rb +36 -0
  78. data/lib/action_dispatch/journey/nfa/simulator.rb +47 -0
  79. data/lib/action_dispatch/journey/nfa/transition_table.rb +163 -0
  80. data/lib/action_dispatch/journey/nodes/node.rb +124 -0
  81. data/lib/action_dispatch/journey/parser.rb +206 -0
  82. data/lib/action_dispatch/journey/parser.y +47 -0
  83. data/lib/action_dispatch/journey/parser_extras.rb +23 -0
  84. data/lib/action_dispatch/journey/path/pattern.rb +196 -0
  85. data/lib/action_dispatch/journey/route.rb +116 -0
  86. data/lib/action_dispatch/journey/router.rb +164 -0
  87. data/lib/action_dispatch/journey/router/strexp.rb +24 -0
  88. data/lib/action_dispatch/journey/router/utils.rb +54 -0
  89. data/lib/action_dispatch/journey/routes.rb +75 -0
  90. data/lib/action_dispatch/journey/scanner.rb +61 -0
  91. data/lib/action_dispatch/journey/visitors.rb +189 -0
  92. data/lib/action_dispatch/journey/visualizer/fsm.css +34 -0
  93. data/lib/action_dispatch/journey/visualizer/fsm.js +134 -0
  94. data/lib/action_dispatch/journey/visualizer/index.html.erb +52 -0
  95. data/lib/action_dispatch/middleware/callbacks.rb +9 -4
  96. data/lib/action_dispatch/middleware/cookies.rb +168 -57
  97. data/lib/action_dispatch/middleware/debug_exceptions.rb +26 -17
  98. data/lib/action_dispatch/middleware/exception_wrapper.rb +27 -3
  99. data/lib/action_dispatch/middleware/flash.rb +58 -58
  100. data/lib/action_dispatch/middleware/params_parser.rb +14 -29
  101. data/lib/action_dispatch/middleware/public_exceptions.rb +31 -14
  102. data/lib/action_dispatch/middleware/reloader.rb +6 -6
  103. data/lib/action_dispatch/middleware/remote_ip.rb +145 -39
  104. data/lib/action_dispatch/middleware/request_id.rb +2 -6
  105. data/lib/action_dispatch/middleware/session/abstract_store.rb +22 -20
  106. data/lib/action_dispatch/middleware/session/cache_store.rb +3 -3
  107. data/lib/action_dispatch/middleware/session/cookie_store.rb +81 -7
  108. data/lib/action_dispatch/middleware/session/mem_cache_store.rb +8 -3
  109. data/lib/action_dispatch/middleware/show_exceptions.rb +12 -45
  110. data/lib/action_dispatch/middleware/ssl.rb +70 -0
  111. data/lib/action_dispatch/middleware/stack.rb +6 -1
  112. data/lib/action_dispatch/middleware/static.rb +5 -24
  113. data/lib/action_dispatch/middleware/templates/rescues/_request_and_response.erb +14 -11
  114. data/lib/action_dispatch/middleware/templates/rescues/_source.erb +25 -0
  115. data/lib/action_dispatch/middleware/templates/rescues/_trace.erb +3 -3
  116. data/lib/action_dispatch/middleware/templates/rescues/diagnostics.erb +15 -9
  117. data/lib/action_dispatch/middleware/templates/rescues/layout.erb +121 -5
  118. data/lib/action_dispatch/middleware/templates/rescues/missing_template.erb +7 -2
  119. data/lib/action_dispatch/middleware/templates/rescues/routing_error.erb +30 -15
  120. data/lib/action_dispatch/middleware/templates/rescues/template_error.erb +39 -13
  121. data/lib/action_dispatch/middleware/templates/rescues/unknown_action.erb +6 -2
  122. data/lib/action_dispatch/middleware/templates/routes/_route.html.erb +16 -0
  123. data/lib/action_dispatch/middleware/templates/routes/_table.html.erb +144 -0
  124. data/lib/action_dispatch/railtie.rb +16 -6
  125. data/lib/action_dispatch/request/session.rb +181 -0
  126. data/lib/action_dispatch/routing.rb +41 -40
  127. data/lib/action_dispatch/routing/inspector.rb +240 -0
  128. data/lib/action_dispatch/routing/mapper.rb +501 -273
  129. data/lib/action_dispatch/routing/polymorphic_routes.rb +16 -20
  130. data/lib/action_dispatch/routing/redirection.rb +46 -29
  131. data/lib/action_dispatch/routing/route_set.rb +203 -164
  132. data/lib/action_dispatch/routing/routes_proxy.rb +2 -0
  133. data/lib/action_dispatch/routing/url_for.rb +48 -33
  134. data/lib/action_dispatch/testing/assertions/dom.rb +3 -13
  135. data/lib/action_dispatch/testing/assertions/response.rb +32 -40
  136. data/lib/action_dispatch/testing/assertions/routing.rb +40 -39
  137. data/lib/action_dispatch/testing/assertions/selector.rb +15 -20
  138. data/lib/action_dispatch/testing/assertions/tag.rb +20 -23
  139. data/lib/action_dispatch/testing/integration.rb +41 -22
  140. data/lib/action_dispatch/testing/test_process.rb +9 -6
  141. data/lib/action_dispatch/testing/test_request.rb +7 -3
  142. data/lib/action_pack.rb +1 -1
  143. data/lib/action_pack/version.rb +4 -4
  144. data/lib/action_view.rb +17 -8
  145. data/lib/action_view/base.rb +15 -34
  146. data/lib/action_view/buffers.rb +1 -1
  147. data/lib/action_view/context.rb +4 -4
  148. data/lib/action_view/dependency_tracker.rb +91 -0
  149. data/lib/action_view/digestor.rb +85 -0
  150. data/lib/action_view/flows.rb +1 -4
  151. data/lib/action_view/helpers.rb +2 -4
  152. data/lib/action_view/helpers/active_model_helper.rb +3 -4
  153. data/lib/action_view/helpers/asset_tag_helper.rb +211 -353
  154. data/lib/action_view/helpers/asset_url_helper.rb +354 -0
  155. data/lib/action_view/helpers/atom_feed_helper.rb +13 -10
  156. data/lib/action_view/helpers/cache_helper.rb +150 -18
  157. data/lib/action_view/helpers/capture_helper.rb +42 -29
  158. data/lib/action_view/helpers/csrf_helper.rb +0 -2
  159. data/lib/action_view/helpers/date_helper.rb +268 -247
  160. data/lib/action_view/helpers/debug_helper.rb +10 -11
  161. data/lib/action_view/helpers/form_helper.rb +904 -547
  162. data/lib/action_view/helpers/form_options_helper.rb +341 -166
  163. data/lib/action_view/helpers/form_tag_helper.rb +188 -88
  164. data/lib/action_view/helpers/javascript_helper.rb +23 -16
  165. data/lib/action_view/helpers/number_helper.rb +148 -354
  166. data/lib/action_view/helpers/output_safety_helper.rb +3 -3
  167. data/lib/action_view/helpers/record_tag_helper.rb +17 -22
  168. data/lib/action_view/helpers/rendering_helper.rb +2 -4
  169. data/lib/action_view/helpers/sanitize_helper.rb +3 -6
  170. data/lib/action_view/helpers/tag_helper.rb +43 -37
  171. data/lib/action_view/helpers/tags.rb +39 -0
  172. data/lib/action_view/helpers/tags/base.rb +148 -0
  173. data/lib/action_view/helpers/tags/check_box.rb +64 -0
  174. data/lib/action_view/helpers/tags/checkable.rb +16 -0
  175. data/lib/action_view/helpers/tags/collection_check_boxes.rb +43 -0
  176. data/lib/action_view/helpers/tags/collection_helpers.rb +83 -0
  177. data/lib/action_view/helpers/tags/collection_radio_buttons.rb +36 -0
  178. data/lib/action_view/helpers/tags/collection_select.rb +28 -0
  179. data/lib/action_view/helpers/tags/color_field.rb +25 -0
  180. data/lib/action_view/helpers/tags/date_field.rb +13 -0
  181. data/lib/action_view/helpers/tags/date_select.rb +72 -0
  182. data/lib/action_view/helpers/tags/datetime_field.rb +22 -0
  183. data/lib/action_view/helpers/tags/datetime_local_field.rb +19 -0
  184. data/lib/action_view/helpers/tags/datetime_select.rb +8 -0
  185. data/lib/action_view/helpers/tags/email_field.rb +8 -0
  186. data/lib/action_view/helpers/tags/file_field.rb +8 -0
  187. data/lib/action_view/helpers/tags/grouped_collection_select.rb +29 -0
  188. data/lib/action_view/helpers/tags/hidden_field.rb +8 -0
  189. data/lib/action_view/helpers/tags/label.rb +65 -0
  190. data/lib/action_view/helpers/tags/month_field.rb +13 -0
  191. data/lib/action_view/helpers/tags/number_field.rb +18 -0
  192. data/lib/action_view/helpers/tags/password_field.rb +12 -0
  193. data/lib/action_view/helpers/tags/radio_button.rb +31 -0
  194. data/lib/action_view/helpers/tags/range_field.rb +8 -0
  195. data/lib/action_view/helpers/tags/search_field.rb +24 -0
  196. data/lib/action_view/helpers/tags/select.rb +41 -0
  197. data/lib/action_view/helpers/tags/tel_field.rb +8 -0
  198. data/lib/action_view/helpers/tags/text_area.rb +18 -0
  199. data/lib/action_view/helpers/tags/text_field.rb +29 -0
  200. data/lib/action_view/helpers/tags/time_field.rb +13 -0
  201. data/lib/action_view/helpers/tags/time_select.rb +8 -0
  202. data/lib/action_view/helpers/tags/time_zone_select.rb +20 -0
  203. data/lib/action_view/helpers/tags/url_field.rb +8 -0
  204. data/lib/action_view/helpers/tags/week_field.rb +13 -0
  205. data/lib/action_view/helpers/text_helper.rb +126 -113
  206. data/lib/action_view/helpers/translation_helper.rb +32 -16
  207. data/lib/action_view/helpers/url_helper.rb +200 -271
  208. data/lib/action_view/locale/en.yml +1 -105
  209. data/lib/action_view/log_subscriber.rb +6 -4
  210. data/lib/action_view/lookup_context.rb +15 -39
  211. data/lib/action_view/model_naming.rb +12 -0
  212. data/lib/action_view/path_set.rb +9 -39
  213. data/lib/action_view/railtie.rb +6 -22
  214. data/lib/action_view/record_identifier.rb +84 -0
  215. data/lib/action_view/renderer/abstract_renderer.rb +10 -19
  216. data/lib/action_view/renderer/partial_renderer.rb +144 -81
  217. data/lib/action_view/renderer/renderer.rb +2 -19
  218. data/lib/action_view/renderer/streaming_template_renderer.rb +2 -5
  219. data/lib/action_view/renderer/template_renderer.rb +14 -13
  220. data/lib/action_view/routing_url_for.rb +107 -0
  221. data/lib/action_view/template.rb +22 -21
  222. data/lib/action_view/template/error.rb +22 -12
  223. data/lib/action_view/template/handlers.rb +12 -9
  224. data/lib/action_view/template/handlers/builder.rb +1 -1
  225. data/lib/action_view/template/handlers/erb.rb +11 -16
  226. data/lib/action_view/template/handlers/raw.rb +11 -0
  227. data/lib/action_view/template/resolver.rb +111 -83
  228. data/lib/action_view/template/text.rb +12 -8
  229. data/lib/action_view/template/types.rb +57 -0
  230. data/lib/action_view/test_case.rb +66 -43
  231. data/lib/action_view/testing/resolvers.rb +3 -2
  232. data/lib/action_view/vendor/html-scanner.rb +20 -0
  233. data/lib/{action_controller → action_view}/vendor/html-scanner/html/document.rb +0 -0
  234. data/lib/{action_controller → action_view}/vendor/html-scanner/html/node.rb +12 -12
  235. data/lib/{action_controller → action_view}/vendor/html-scanner/html/sanitizer.rb +18 -7
  236. data/lib/{action_controller → action_view}/vendor/html-scanner/html/selector.rb +1 -1
  237. data/lib/{action_controller → action_view}/vendor/html-scanner/html/tokenizer.rb +1 -1
  238. data/lib/{action_controller → action_view}/vendor/html-scanner/html/version.rb +0 -0
  239. metadata +135 -125
  240. data/lib/action_controller/caching/actions.rb +0 -185
  241. data/lib/action_controller/caching/pages.rb +0 -187
  242. data/lib/action_controller/caching/sweeping.rb +0 -97
  243. data/lib/action_controller/deprecated/performance_test.rb +0 -1
  244. data/lib/action_controller/metal/compatibility.rb +0 -65
  245. data/lib/action_controller/metal/session_management.rb +0 -14
  246. data/lib/action_controller/railties/paths.rb +0 -25
  247. data/lib/action_dispatch/middleware/best_standards_support.rb +0 -30
  248. data/lib/action_dispatch/middleware/body_proxy.rb +0 -30
  249. data/lib/action_dispatch/middleware/head.rb +0 -18
  250. data/lib/action_dispatch/middleware/rescue.rb +0 -26
  251. data/lib/action_dispatch/testing/performance_test.rb +0 -10
  252. data/lib/action_view/asset_paths.rb +0 -142
  253. data/lib/action_view/helpers/asset_paths.rb +0 -7
  254. data/lib/action_view/helpers/asset_tag_helpers/asset_include_tag.rb +0 -146
  255. data/lib/action_view/helpers/asset_tag_helpers/asset_paths.rb +0 -93
  256. data/lib/action_view/helpers/asset_tag_helpers/javascript_tag_helpers.rb +0 -193
  257. data/lib/action_view/helpers/asset_tag_helpers/stylesheet_tag_helpers.rb +0 -148
  258. data/lib/sprockets/assets.rake +0 -99
  259. data/lib/sprockets/bootstrap.rb +0 -37
  260. data/lib/sprockets/compressors.rb +0 -83
  261. data/lib/sprockets/helpers.rb +0 -6
  262. data/lib/sprockets/helpers/isolated_helper.rb +0 -13
  263. data/lib/sprockets/helpers/rails_helper.rb +0 -182
  264. data/lib/sprockets/railtie.rb +0 -62
  265. data/lib/sprockets/static_compiler.rb +0 -56
@@ -4,30 +4,25 @@ module ActionController
4
4
 
5
5
  include RackDelegation
6
6
 
7
- def recycle!
8
- @_url_options = nil
9
- end
10
-
11
-
12
- # TODO: Clean this up
13
- def process_with_new_base_test(request, response)
14
- @_request = request
15
- @_response = response
16
- @_response.request = request
17
- ret = process(request.parameters[:action])
18
- if cookies = @_request.env['action_dispatch.cookies']
19
- cookies.write(@_response)
20
- end
21
- @_response.prepare!
22
- ret
23
- end
24
-
25
7
  # TODO : Rewrite tests using controller.headers= to use Rack env
26
8
  def headers=(new_headers)
27
9
  @_response ||= ActionDispatch::Response.new
28
10
  @_response.headers.replace(new_headers)
29
11
  end
30
12
 
13
+ # Behavior specific to functional tests
14
+ module Functional # :nodoc:
15
+ def set_response!(request)
16
+ end
17
+
18
+ def recycle!
19
+ @_url_options = nil
20
+ self.response_body = nil
21
+ self.formats = nil
22
+ self.params = nil
23
+ end
24
+ end
25
+
31
26
  module ClassMethods
32
27
  def before_filters
33
28
  _process_action_callbacks.find_all{|x| x.kind == :before}.map{|x| x.name}
@@ -1,25 +1,22 @@
1
- # Includes +url_for+ into the host class. The class has to provide a +RouteSet+ by implementing
2
- # the <tt>_routes</tt> method. Otherwise, an exception will be raised.
3
- #
4
- # In addition to <tt>AbstractController::UrlFor</tt>, this module accesses the HTTP layer to define
5
- # url options like the +host+. In order to do so, this module requires the host class
6
- # to implement +env+ and +request+, which need to be a Rack-compatible.
7
- #
8
- # Example:
9
- #
10
- # class RootUrl
11
- # include ActionController::UrlFor
12
- # include Rails.application.routes.url_helpers
13
- #
14
- # delegate :env, :request, :to => :controller
15
- #
16
- # def initialize(controller)
17
- # @controller = controller
18
- # @url = root_path # named route from the application.
19
- # end
20
- # end
21
- #
22
1
  module ActionController
2
+ # Includes +url_for+ into the host class. The class has to provide a +RouteSet+ by implementing
3
+ # the <tt>_routes</tt> method. Otherwise, an exception will be raised.
4
+ #
5
+ # In addition to <tt>AbstractController::UrlFor</tt>, this module accesses the HTTP layer to define
6
+ # url options like the +host+. In order to do so, this module requires the host class
7
+ # to implement +env+ and +request+, which need to be a Rack-compatible.
8
+ #
9
+ # class RootUrl
10
+ # include ActionController::UrlFor
11
+ # include Rails.application.routes.url_helpers
12
+ #
13
+ # delegate :env, :request, to: :controller
14
+ #
15
+ # def initialize(controller)
16
+ # @controller = controller
17
+ # @url = root_path # named route from the application.
18
+ # end
19
+ # end
23
20
  module UrlFor
24
21
  extend ActiveSupport::Concern
25
22
 
@@ -30,18 +27,23 @@ module ActionController
30
27
  :host => request.host,
31
28
  :port => request.optional_port,
32
29
  :protocol => request.protocol,
33
- :_path_segments => request.symbolized_path_parameters
30
+ :_recall => request.symbolized_path_parameters
34
31
  ).freeze
35
32
 
36
- if _routes.equal?(env["action_dispatch.routes"])
33
+ if (same_origin = _routes.equal?(env["action_dispatch.routes"])) ||
34
+ (script_name = env["ROUTES_#{_routes.object_id}_SCRIPT_NAME"]) ||
35
+ (original_script_name = env['SCRIPT_NAME'])
37
36
  @_url_options.dup.tap do |options|
38
- options[:script_name] = request.script_name.dup
37
+ if original_script_name
38
+ options[:original_script_name] = original_script_name
39
+ else
40
+ options[:script_name] = same_origin ? request.script_name.dup : script_name
41
+ end
39
42
  options.freeze
40
43
  end
41
44
  else
42
45
  @_url_options
43
46
  end
44
47
  end
45
-
46
48
  end
47
49
  end
@@ -0,0 +1,12 @@
1
+ module ActionController
2
+ module ModelNaming
3
+ # Converts the given object to an ActiveModel compliant one.
4
+ def convert_to_model(object)
5
+ object.respond_to?(:to_model) ? object.to_model : object
6
+ end
7
+
8
+ def model_name_from_record_or_class(record_or_class)
9
+ (record_or_class.is_a?(Class) ? record_or_class : convert_to_model(record_or_class).class).model_name
10
+ end
11
+ end
12
+ end
@@ -3,42 +3,58 @@ require "action_controller"
3
3
  require "action_dispatch/railtie"
4
4
  require "action_view/railtie"
5
5
  require "abstract_controller/railties/routes_helpers"
6
- require "action_controller/railties/paths"
6
+ require "action_controller/railties/helpers"
7
7
 
8
8
  module ActionController
9
- class Railtie < Rails::Railtie
9
+ class Railtie < Rails::Railtie #:nodoc:
10
10
  config.action_controller = ActiveSupport::OrderedOptions.new
11
11
 
12
- initializer "action_controller.logger" do
13
- ActiveSupport.on_load(:action_controller) { self.logger ||= Rails.logger }
12
+ config.eager_load_namespaces << ActionController
13
+
14
+ initializer "action_controller.assets_config", :group => :all do |app|
15
+ app.config.action_controller.assets_dir ||= app.config.paths["public"].first
14
16
  end
15
17
 
16
- initializer "action_controller.initialize_framework_caches" do
17
- ActiveSupport.on_load(:action_controller) { self.cache_store ||= RAILS_CACHE }
18
+ initializer "action_controller.set_helpers_path" do |app|
19
+ ActionController::Helpers.helpers_path = app.helpers_paths
18
20
  end
19
21
 
20
- initializer "action_controller.assets_config", :group => :all do |app|
21
- app.config.action_controller.assets_dir ||= app.config.paths["public"].first
22
+ initializer "action_controller.parameters_config" do |app|
23
+ options = app.config.action_controller
24
+
25
+ ActionController::Parameters.permit_all_parameters = options.delete(:permit_all_parameters) { false }
26
+ ActionController::Parameters.action_on_unpermitted_parameters = options.delete(:action_on_unpermitted_parameters) do
27
+ (Rails.env.test? || Rails.env.development?) ? :log : false
28
+ end
22
29
  end
23
30
 
24
31
  initializer "action_controller.set_configs" do |app|
25
32
  paths = app.config.paths
26
33
  options = app.config.action_controller
27
34
 
28
- options.javascripts_dir ||= paths["public/javascripts"].first
29
- options.stylesheets_dir ||= paths["public/stylesheets"].first
30
- options.page_cache_directory ||= paths["public"].first
35
+ options.logger ||= Rails.logger
36
+ options.cache_store ||= Rails.cache
31
37
 
32
- # make sure readers methods get compiled
33
- options.asset_path ||= app.config.asset_path
34
- options.asset_host ||= app.config.asset_host
35
- options.relative_url_root ||= app.config.relative_url_root
38
+ options.javascripts_dir ||= paths["public/javascripts"].first
39
+ options.stylesheets_dir ||= paths["public/stylesheets"].first
40
+
41
+ # Ensure readers methods get compiled
42
+ options.asset_host ||= app.config.asset_host
43
+ options.relative_url_root ||= app.config.relative_url_root
36
44
 
37
45
  ActiveSupport.on_load(:action_controller) do
38
46
  include app.routes.mounted_helpers
39
47
  extend ::AbstractController::Railties::RoutesHelpers.with(app.routes)
40
- extend ::ActionController::Railties::Paths.with(app)
41
- options.each { |k,v| send("#{k}=", v) }
48
+ extend ::ActionController::Railties::Helpers
49
+
50
+ options.each do |k,v|
51
+ k = "#{k}="
52
+ if respond_to?(k)
53
+ send(k, v)
54
+ elsif !Base.respond_to?(k)
55
+ raise "Invalid option key: #{k}"
56
+ end
57
+ end
42
58
  end
43
59
  end
44
60
 
@@ -0,0 +1,22 @@
1
+ module ActionController
2
+ module Railties
3
+ module Helpers
4
+ def inherited(klass)
5
+ super
6
+ return unless klass.respond_to?(:helpers_path=)
7
+
8
+ if namespace = klass.parents.detect { |m| m.respond_to?(:railtie_helpers_paths) }
9
+ paths = namespace.railtie_helpers_paths
10
+ else
11
+ paths = ActionController::Helpers.helpers_path
12
+ end
13
+
14
+ klass.helpers_path = paths
15
+
16
+ if klass.superclass == ActionController::Base && ActionController::Base.include_all_helpers
17
+ klass.helper :all
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
@@ -1,85 +1,31 @@
1
- require 'active_support/core_ext/module'
1
+ require 'action_view/record_identifier'
2
2
 
3
3
  module ActionController
4
- # The record identifier encapsulates a number of naming conventions for dealing with records, like Active Records or
5
- # Active Resources or pretty much any other model type that has an id. These patterns are then used to try elevate
6
- # the view actions to a higher logical level. Example:
7
- #
8
- # # routes
9
- # resources :posts
10
- #
11
- # # view
12
- # <%= div_for(post) do %> <div id="post_45" class="post">
13
- # <%= post.body %> What a wonderful world!
14
- # <% end %> </div>
15
- #
16
- # # controller
17
- # def update
18
- # post = Post.find(params[:id])
19
- # post.update_attributes(params[:post])
20
- #
21
- # redirect_to(post) # Calls polymorphic_url(post) which in turn calls post_url(post)
22
- # end
23
- #
24
- # As the example above shows, you can stop caring to a large extent what the actual id of the post is.
25
- # You just know that one is being assigned and that the subsequent calls in redirect_to expect that
26
- # same naming convention and allows you to write less code if you follow it.
27
4
  module RecordIdentifier
28
- extend self
5
+ MODULE_MESSAGE = 'Calling ActionController::RecordIdentifier.%s is deprecated and ' \
6
+ 'will be removed in Rails 4.1, please call using ActionView::RecordIdentifier instead.'
7
+ INSTANCE_MESSAGE = '%s method will no longer be included by default in controllers ' \
8
+ 'since Rails 4.1. If you would like to use it in controllers, please include ' \
9
+ 'ActionView::RecordIdentifier module.'
29
10
 
30
- JOIN = '_'.freeze
31
- NEW = 'new'.freeze
32
-
33
- # The DOM class convention is to use the singular form of an object or class. Examples:
34
- #
35
- # dom_class(post) # => "post"
36
- # dom_class(Person) # => "person"
37
- #
38
- # If you need to address multiple instances of the same class in the same view, you can prefix the dom_class:
39
- #
40
- # dom_class(post, :edit) # => "edit_post"
41
- # dom_class(Person, :edit) # => "edit_person"
42
- def dom_class(record_or_class, prefix = nil)
43
- singular = ActiveModel::Naming.param_key(record_or_class)
44
- prefix ? "#{prefix}#{JOIN}#{singular}" : singular
45
- end
46
-
47
- # The DOM id convention is to use the singular form of an object or class with the id following an underscore.
48
- # If no id is found, prefix with "new_" instead. Examples:
49
- #
50
- # dom_id(Post.find(45)) # => "post_45"
51
- # dom_id(Post.new) # => "new_post"
52
- #
53
- # If you need to address multiple instances of the same class in the same view, you can prefix the dom_id:
54
- #
55
- # dom_id(Post.find(45), :edit) # => "edit_post_45"
56
11
  def dom_id(record, prefix = nil)
57
- if record_id = record_key_for_dom_id(record)
58
- "#{dom_class(record, prefix)}#{JOIN}#{record_id}"
59
- else
60
- dom_class(record, prefix || NEW)
61
- end
12
+ ActiveSupport::Deprecation.warn(INSTANCE_MESSAGE % 'dom_id')
13
+ ActionView::RecordIdentifier.dom_id(record, prefix)
62
14
  end
63
15
 
64
- protected
16
+ def dom_class(record, prefix = nil)
17
+ ActiveSupport::Deprecation.warn(INSTANCE_MESSAGE % 'dom_class')
18
+ ActionView::RecordIdentifier.dom_class(record, prefix)
19
+ end
65
20
 
66
- # Returns a string representation of the key attribute(s) that is suitable for use in an HTML DOM id.
67
- # This can be overwritten to customize the default generated string representation if desired.
68
- # If you need to read back a key from a dom_id in order to query for the underlying database record,
69
- # you should write a helper like 'person_record_from_dom_id' that will extract the key either based
70
- # on the default implementation (which just joins all key attributes with '_') or on your own
71
- # overwritten version of the method. By default, this implementation passes the key string through a
72
- # method that replaces all characters that are invalid inside DOM ids, with valid ones. You need to
73
- # make sure yourself that your dom ids are valid, in case you overwrite this method.
74
- def record_key_for_dom_id(record)
75
- record = record.to_model if record.respond_to?(:to_model)
76
- key = record.to_key
77
- key ? sanitize_dom_id(key.join('_')) : key
21
+ def self.dom_id(record, prefix = nil)
22
+ ActiveSupport::Deprecation.warn(MODULE_MESSAGE % 'dom_id')
23
+ ActionView::RecordIdentifier.dom_id(record, prefix)
78
24
  end
79
25
 
80
- # Replaces characters that are invalid in HTML DOM ids with valid ones.
81
- def sanitize_dom_id(candidate_id)
82
- candidate_id # TODO implement conversion to valid DOM id values
26
+ def self.dom_class(record, prefix = nil)
27
+ ActiveSupport::Deprecation.warn(MODULE_MESSAGE % 'dom_class')
28
+ ActionView::RecordIdentifier.dom_class(record, prefix)
83
29
  end
84
30
  end
85
31
  end
@@ -1,8 +1,7 @@
1
1
  require 'rack/session/abstract/id'
2
- require 'active_support/core_ext/object/blank'
3
2
  require 'active_support/core_ext/object/to_query'
4
- require 'active_support/core_ext/class/attribute'
5
3
  require 'active_support/core_ext/module/anonymous'
4
+ require 'active_support/core_ext/hash/keys'
6
5
 
7
6
  module ActionController
8
7
  module TemplateAssertions
@@ -14,16 +13,16 @@ module ActionController
14
13
  end
15
14
 
16
15
  def setup_subscriptions
17
- @partials = Hash.new(0)
18
- @templates = Hash.new(0)
19
- @layouts = Hash.new(0)
16
+ @_partials = Hash.new(0)
17
+ @_templates = Hash.new(0)
18
+ @_layouts = Hash.new(0)
20
19
 
21
20
  ActiveSupport::Notifications.subscribe("render_template.action_view") do |name, start, finish, id, payload|
22
21
  path = payload[:layout]
23
22
  if path
24
- @layouts[path] += 1
23
+ @_layouts[path] += 1
25
24
  if path =~ /^layouts\/(.*)/
26
- @layouts[$1] += 1
25
+ @_layouts[$1] += 1
27
26
  end
28
27
  end
29
28
  end
@@ -32,13 +31,13 @@ module ActionController
32
31
  path = payload[:virtual_path]
33
32
  next unless path
34
33
  partial = path =~ /^.*\/_[^\/]*$/
34
+
35
35
  if partial
36
- @partials[path] += 1
37
- @partials[path.split("/").last] += 1
38
- @templates[path] += 1
39
- else
40
- @templates[path] += 1
36
+ @_partials[path] += 1
37
+ @_partials[path.split("/").last] += 1
41
38
  end
39
+
40
+ @_templates[path] += 1
42
41
  end
43
42
  end
44
43
 
@@ -48,107 +47,121 @@ module ActionController
48
47
  end
49
48
 
50
49
  def process(*args)
51
- @partials = Hash.new(0)
52
- @templates = Hash.new(0)
53
- @layouts = Hash.new(0)
50
+ @_partials = Hash.new(0)
51
+ @_templates = Hash.new(0)
52
+ @_layouts = Hash.new(0)
54
53
  super
55
54
  end
56
55
 
57
56
  # Asserts that the request was rendered with the appropriate template file or partials.
58
57
  #
59
- # ==== Examples
60
- #
61
58
  # # assert that the "new" view template was rendered
62
59
  # assert_template "new"
63
60
  #
61
+ # # assert that the exact template "admin/posts/new" was rendered
62
+ # assert_template %r{\Aadmin/posts/new\Z}
63
+ #
64
64
  # # assert that the layout 'admin' was rendered
65
- # assert_template :layout => 'admin'
66
- # assert_template :layout => 'layouts/admin'
67
- # assert_template :layout => :admin
65
+ # assert_template layout: 'admin'
66
+ # assert_template layout: 'layouts/admin'
67
+ # assert_template layout: :admin
68
68
  #
69
69
  # # assert that no layout was rendered
70
- # assert_template :layout => nil
71
- # assert_template :layout => false
70
+ # assert_template layout: nil
71
+ # assert_template layout: false
72
72
  #
73
73
  # # assert that the "_customer" partial was rendered twice
74
- # assert_template :partial => '_customer', :count => 2
74
+ # assert_template partial: '_customer', count: 2
75
75
  #
76
76
  # # assert that no partials were rendered
77
- # assert_template :partial => false
77
+ # assert_template partial: false
78
78
  #
79
79
  # In a view test case, you can also assert that specific locals are passed
80
80
  # to partials:
81
81
  #
82
82
  # # assert that the "_customer" partial was rendered with a specific object
83
- # assert_template :partial => '_customer', :locals => { :customer => @customer }
84
- #
83
+ # assert_template partial: '_customer', locals: { customer: @customer }
85
84
  def assert_template(options = {}, message = nil)
86
- validate_request!
87
- # Force body to be read in case the template is being streamed
85
+ # Force body to be read in case the template is being streamed.
88
86
  response.body
89
87
 
90
88
  case options
91
- when NilClass, String, Symbol
89
+ when NilClass, Regexp, String, Symbol
92
90
  options = options.to_s if Symbol === options
93
- rendered = @templates
94
- msg = build_message(message,
95
- "expecting <?> but rendering with <?>",
96
- options, rendered.keys.join(', '))
97
- assert_block(msg) do
98
- if options
91
+ rendered = @_templates
92
+ msg = message || sprintf("expecting <%s> but rendering with <%s>",
93
+ options.inspect, rendered.keys)
94
+ matches_template =
95
+ case options
96
+ when String
97
+ !options.empty? && rendered.any? do |t, num|
98
+ options_splited = options.split(File::SEPARATOR)
99
+ t_splited = t.split(File::SEPARATOR)
100
+ t_splited.last(options_splited.size) == options_splited
101
+ end
102
+ when Regexp
99
103
  rendered.any? { |t,num| t.match(options) }
100
- else
101
- @templates.blank?
104
+ when NilClass
105
+ rendered.blank?
102
106
  end
103
- end
107
+ assert matches_template, msg
104
108
  when Hash
109
+ options.assert_valid_keys(:layout, :partial, :locals, :count)
110
+
105
111
  if options.key?(:layout)
106
112
  expected_layout = options[:layout]
107
- msg = build_message(message,
108
- "expecting layout <?> but action rendered <?>",
109
- expected_layout, @layouts.keys)
113
+ msg = message || sprintf("expecting layout <%s> but action rendered <%s>",
114
+ expected_layout, @_layouts.keys)
110
115
 
111
116
  case expected_layout
112
117
  when String, Symbol
113
- assert(@layouts.keys.include?(expected_layout.to_s), msg)
118
+ assert_includes @_layouts.keys, expected_layout.to_s, msg
114
119
  when Regexp
115
- assert(@layouts.keys.any? {|l| l =~ expected_layout }, msg)
120
+ assert(@_layouts.keys.any? {|l| l =~ expected_layout }, msg)
116
121
  when nil, false
117
- assert(@layouts.empty?, msg)
122
+ assert(@_layouts.empty?, msg)
118
123
  end
119
124
  end
120
125
 
121
126
  if expected_partial = options[:partial]
122
127
  if expected_locals = options[:locals]
123
- if defined?(@locals)
124
- actual_locals = @locals[expected_partial.to_s.sub(/^_/,'')]
125
- expected_locals.each_pair do |k,v|
126
- assert_equal(v, actual_locals[k])
127
- end
128
+ if defined?(@_rendered_views)
129
+ view = expected_partial.to_s.sub(/^_/, '').sub(/\/_(?=[^\/]+\z)/, '/')
130
+
131
+ partial_was_not_rendered_msg = "expected %s to be rendered but it was not." % view
132
+ assert_includes @_rendered_views.rendered_views, view, partial_was_not_rendered_msg
133
+
134
+ msg = 'expecting %s to be rendered with %s but was with %s' % [expected_partial,
135
+ expected_locals,
136
+ @_rendered_views.locals_for(view)]
137
+ assert(@_rendered_views.view_rendered?(view, options[:locals]), msg)
128
138
  else
129
139
  warn "the :locals option to #assert_template is only supported in a ActionView::TestCase"
130
140
  end
131
141
  elsif expected_count = options[:count]
132
- actual_count = @partials[expected_partial]
133
- msg = build_message(message,
134
- "expecting ? to be rendered ? time(s) but rendered ? time(s)",
142
+ actual_count = @_partials[expected_partial]
143
+ msg = message || sprintf("expecting %s to be rendered %s time(s) but rendered %s time(s)",
135
144
  expected_partial, expected_count, actual_count)
136
145
  assert(actual_count == expected_count.to_i, msg)
137
146
  else
138
- msg = build_message(message,
139
- "expecting partial <?> but action rendered <?>",
140
- options[:partial], @partials.keys)
141
- assert(@partials.include?(expected_partial), msg)
147
+ msg = message || sprintf("expecting partial <%s> but action rendered <%s>",
148
+ options[:partial], @_partials.keys)
149
+ assert_includes @_partials, expected_partial, msg
142
150
  end
143
151
  elsif options.key?(:partial)
144
- assert @partials.empty?,
152
+ assert @_partials.empty?,
145
153
  "Expected no partials to be rendered"
146
154
  end
155
+ else
156
+ raise ArgumentError, "assert_template only accepts a String, Symbol, Hash, Regexp, or nil"
147
157
  end
148
158
  end
149
159
  end
150
160
 
151
161
  class TestRequest < ActionDispatch::TestRequest #:nodoc:
162
+ DEFAULT_ENV = ActionDispatch::TestRequest::DEFAULT_ENV.dup
163
+ DEFAULT_ENV.delete 'PATH_INFO'
164
+
152
165
  def initialize(env = {})
153
166
  super
154
167
 
@@ -156,13 +169,6 @@ module ActionController
156
169
  self.session_options = TestSession::DEFAULT_OPTIONS.merge(:id => SecureRandom.hex(16))
157
170
  end
158
171
 
159
- class Result < ::Array #:nodoc:
160
- def to_s() join '/' end
161
- def self.new_escaped(strings)
162
- new strings.collect {|str| uri_parser.unescape str}
163
- end
164
- end
165
-
166
172
  def assign_parameters(routes, controller_path, action, parameters = {})
167
173
  parameters = parameters.symbolize_keys.merge(:controller => controller_path, :action => action)
168
174
  extra_keys = routes.extra_keys(parameters)
@@ -180,7 +186,7 @@ module ActionController
180
186
  non_path_parameters[key] = value
181
187
  else
182
188
  if value.is_a?(Array)
183
- value = Result.new(value.map(&:to_param))
189
+ value = value.map(&:to_param)
184
190
  else
185
191
  value = value.to_param
186
192
  end
@@ -220,33 +226,53 @@ module ActionController
220
226
  cookie_jar.update(@set_cookies)
221
227
  cookie_jar.recycle!
222
228
  end
229
+
230
+ private
231
+
232
+ def default_env
233
+ DEFAULT_ENV
234
+ end
223
235
  end
224
236
 
225
237
  class TestResponse < ActionDispatch::TestResponse
226
238
  def recycle!
227
- @status = 200
228
- @header = {}
229
- @writer = lambda { |x| @body << x }
230
- @block = nil
231
- @length = 0
232
- @body = []
233
- @charset = @content_type = nil
234
- @request = @template = nil
239
+ initialize
235
240
  end
236
241
  end
237
242
 
243
+ # Methods #destroy and #load! are overridden to avoid calling methods on the
244
+ # @store object, which does not exist for the TestSession class.
238
245
  class TestSession < Rack::Session::Abstract::SessionHash #:nodoc:
239
246
  DEFAULT_OPTIONS = Rack::Session::Abstract::ID::DEFAULT_OPTIONS
240
247
 
241
248
  def initialize(session = {})
242
249
  super(nil, nil)
243
- replace(session.stringify_keys)
250
+ @id = SecureRandom.hex(16)
251
+ @data = stringify_keys(session)
244
252
  @loaded = true
245
253
  end
246
254
 
247
255
  def exists?
248
256
  true
249
257
  end
258
+
259
+ def keys
260
+ @data.keys
261
+ end
262
+
263
+ def values
264
+ @data.values
265
+ end
266
+
267
+ def destroy
268
+ clear
269
+ end
270
+
271
+ private
272
+
273
+ def load!
274
+ @id
275
+ end
250
276
  end
251
277
 
252
278
  # Superclass for ActionController functional tests. Functional tests allow you to
@@ -258,7 +284,7 @@ module ActionController
258
284
  # == Basic example
259
285
  #
260
286
  # Functional tests are written as follows:
261
- # 1. First, one uses the +get+, +post+, +put+, +delete+ or +head+ method to simulate
287
+ # 1. First, one uses the +get+, +post+, +patch+, +put+, +delete+ or +head+ method to simulate
262
288
  # an HTTP request.
263
289
  # 2. Then, one asserts whether the current state is as expected. "State" can be anything:
264
290
  # the controller's HTTP response, the database contents, etc.
@@ -268,7 +294,7 @@ module ActionController
268
294
  # class BooksControllerTest < ActionController::TestCase
269
295
  # def test_create
270
296
  # # Simulate a POST response with the given HTTP parameters.
271
- # post(:create, :book => { :title => "Love Hina" })
297
+ # post(:create, book: { title: "Love Hina" })
272
298
  #
273
299
  # # Assert that the controller tried to redirect us to
274
300
  # # the created book's URI.
@@ -279,6 +305,13 @@ module ActionController
279
305
  # end
280
306
  # end
281
307
  #
308
+ # You can also send a real document in the simulated HTTP request.
309
+ #
310
+ # def test_create
311
+ # json = {book: { title: "Love Hina" }}.to_json
312
+ # post :create, json
313
+ # end
314
+ #
282
315
  # == Special instance variables
283
316
  #
284
317
  # ActionController::TestCase will also automatically provide the following instance
@@ -349,29 +382,28 @@ module ActionController
349
382
  # == \Testing named routes
350
383
  #
351
384
  # If you're using named routes, they can be easily tested using the original named routes' methods straight in the test case.
352
- # Example:
353
385
  #
354
- # assert_redirected_to page_url(:title => 'foo')
386
+ # assert_redirected_to page_url(title: 'foo')
355
387
  class TestCase < ActiveSupport::TestCase
356
388
  module Behavior
357
389
  extend ActiveSupport::Concern
358
390
  include ActionDispatch::TestProcess
391
+ include ActiveSupport::Testing::ConstantLookup
359
392
 
360
393
  attr_reader :response, :request
361
394
 
362
395
  module ClassMethods
363
396
 
364
397
  # Sets the controller class name. Useful if the name can't be inferred from test class.
365
- # Normalizes +controller_class+ before using. Examples:
398
+ # Normalizes +controller_class+ before using.
366
399
  #
367
400
  # tests WidgetController
368
401
  # tests :widget
369
402
  # tests 'widget'
370
- #
371
403
  def tests(controller_class)
372
404
  case controller_class
373
405
  when String, Symbol
374
- self.controller_class = "#{controller_class.to_s.underscore}_controller".camelize.constantize
406
+ self.controller_class = "#{controller_class.to_s.camelize}Controller".constantize
375
407
  when Class
376
408
  self.controller_class = controller_class
377
409
  else
@@ -393,7 +425,9 @@ module ActionController
393
425
  end
394
426
 
395
427
  def determine_default_controller_class(name)
396
- name.sub(/Test$/, '').safe_constantize
428
+ determine_constant_from_test_name(name) do |constant|
429
+ Class === constant && constant < ActionController::Metal
430
+ end
397
431
  end
398
432
 
399
433
  def prepare_controller_class(new_class)
@@ -403,28 +437,38 @@ module ActionController
403
437
  end
404
438
 
405
439
  # Executes a request simulating GET HTTP method and set/volley the response
406
- def get(action, parameters = nil, session = nil, flash = nil)
407
- process(action, parameters, session, flash, "GET")
440
+ def get(action, *args)
441
+ process(action, "GET", *args)
408
442
  end
409
443
 
410
444
  # Executes a request simulating POST HTTP method and set/volley the response
411
- def post(action, parameters = nil, session = nil, flash = nil)
412
- process(action, parameters, session, flash, "POST")
445
+ def post(action, *args)
446
+ process(action, "POST", *args)
447
+ end
448
+
449
+ # Executes a request simulating PATCH HTTP method and set/volley the response
450
+ def patch(action, *args)
451
+ process(action, "PATCH", *args)
413
452
  end
414
453
 
415
454
  # Executes a request simulating PUT HTTP method and set/volley the response
416
- def put(action, parameters = nil, session = nil, flash = nil)
417
- process(action, parameters, session, flash, "PUT")
455
+ def put(action, *args)
456
+ process(action, "PUT", *args)
418
457
  end
419
458
 
420
459
  # Executes a request simulating DELETE HTTP method and set/volley the response
421
- def delete(action, parameters = nil, session = nil, flash = nil)
422
- process(action, parameters, session, flash, "DELETE")
460
+ def delete(action, *args)
461
+ process(action, "DELETE", *args)
423
462
  end
424
463
 
425
464
  # Executes a request simulating HEAD HTTP method and set/volley the response
426
- def head(action, parameters = nil, session = nil, flash = nil)
427
- process(action, parameters, session, flash, "HEAD")
465
+ def head(action, *args)
466
+ process(action, "HEAD", *args)
467
+ end
468
+
469
+ # Executes a request simulating OPTIONS HTTP method and set/volley the response
470
+ def options(action, *args)
471
+ process(action, "OPTIONS", *args)
428
472
  end
429
473
 
430
474
  def xml_http_request(request_method, action, parameters = nil, session = nil, flash = nil)
@@ -450,65 +494,94 @@ module ActionController
450
494
  end
451
495
  end
452
496
 
453
- def process(action, parameters = nil, session = nil, flash = nil, http_method = 'GET')
497
+ def process(action, http_method = 'GET', *args)
498
+ check_required_ivars
499
+ http_method, args = handle_old_process_api(http_method, args, caller)
500
+
501
+ if args.first.is_a?(String) && http_method != 'HEAD'
502
+ @request.env['RAW_POST_DATA'] = args.shift
503
+ end
504
+
505
+ parameters, session, flash = args
506
+
454
507
  # Ensure that numbers and symbols passed as params are converted to
455
508
  # proper params, as is the case when engaging rack.
456
509
  parameters = paramify_values(parameters) if html_format?(parameters)
457
510
 
458
- # Sanity check for required instance variables so we can give an
459
- # understandable error message.
460
- %w(@routes @controller @request @response).each do |iv_name|
461
- if !(instance_variable_names.include?(iv_name) || instance_variable_names.include?(iv_name.to_sym)) || instance_variable_get(iv_name).nil?
462
- raise "#{iv_name} is nil: make sure you set it in your test's setup method."
463
- end
511
+ @html_document = nil
512
+
513
+ unless @controller.respond_to?(:recycle!)
514
+ @controller.extend(Testing::Functional)
515
+ @controller.class.class_eval { include Testing }
464
516
  end
465
517
 
466
518
  @request.recycle!
467
519
  @response.recycle!
468
- @controller.response_body = nil
469
- @controller.formats = nil
470
- @controller.params = nil
520
+ @controller.recycle!
471
521
 
472
- @html_document = nil
473
522
  @request.env['REQUEST_METHOD'] = http_method
474
523
 
475
524
  parameters ||= {}
476
525
  controller_class_name = @controller.class.anonymous? ?
477
- "anonymous_controller" :
478
- @controller.class.controller_path
526
+ "anonymous" :
527
+ @controller.class.name.underscore.sub(/_controller$/, '')
479
528
 
480
529
  @request.assign_parameters(@routes, controller_class_name, action.to_s, parameters)
481
530
 
482
- @request.session = ActionController::TestSession.new(session) if session
483
- @request.session["flash"] = @request.flash.update(flash || {})
484
- @request.session["flash"].sweep
531
+ @request.session.update(session) if session
532
+ @request.flash.update(flash || {})
533
+
534
+ @controller.request = @request
535
+ @controller.response = @response
485
536
 
486
- @controller.request = @request
487
537
  build_request_uri(action, parameters)
488
- @controller.class.class_eval { include Testing }
489
- @controller.recycle!
490
- @controller.process_with_new_base_test(@request, @response)
538
+
539
+ name = @request.parameters[:action]
540
+
541
+ @controller.process(name)
542
+
543
+ if cookies = @request.env['action_dispatch.cookies']
544
+ cookies.write(@response)
545
+ end
546
+ @response.prepare!
547
+
491
548
  @assigns = @controller.respond_to?(:view_assigns) ? @controller.view_assigns : {}
549
+ @request.session['flash'] = @request.flash.to_session_value
492
550
  @request.session.delete('flash') if @request.session['flash'].blank?
493
551
  @response
494
552
  end
495
553
 
496
554
  def setup_controller_request_and_response
497
- @request = TestRequest.new
498
- @response = TestResponse.new
555
+ @request = build_request
556
+ @response = build_response
557
+ @response.request = @request
558
+
559
+ @controller = nil unless defined? @controller
499
560
 
500
561
  if klass = self.class.controller_class
501
- @controller ||= klass.new rescue nil
562
+ unless @controller
563
+ begin
564
+ @controller = klass.new
565
+ rescue
566
+ warn "could not construct controller #{klass}" if $VERBOSE
567
+ end
568
+ end
502
569
  end
503
570
 
504
- @request.env.delete('PATH_INFO')
505
-
506
- if defined?(@controller) && @controller
571
+ if @controller
507
572
  @controller.request = @request
508
573
  @controller.params = {}
509
574
  end
510
575
  end
511
576
 
577
+ def build_request
578
+ TestRequest.new
579
+ end
580
+
581
+ def build_response
582
+ TestResponse.new
583
+ end
584
+
512
585
  included do
513
586
  include ActionController::TemplateAssertions
514
587
  include ActionDispatch::Assertions
@@ -516,7 +589,27 @@ module ActionController
516
589
  setup :setup_controller_request_and_response
517
590
  end
518
591
 
519
- private
592
+ private
593
+ def check_required_ivars
594
+ # Sanity check for required instance variables so we can give an
595
+ # understandable error message.
596
+ [:@routes, :@controller, :@request, :@response].each do |iv_name|
597
+ if !instance_variable_defined?(iv_name) || instance_variable_get(iv_name).nil?
598
+ raise "#{iv_name} is nil: make sure you set it in your test's setup method."
599
+ end
600
+ end
601
+ end
602
+
603
+ def handle_old_process_api(http_method, args, callstack)
604
+ # 4.0: Remove this method.
605
+ if http_method.is_a?(Hash)
606
+ ActiveSupport::Deprecation.warn("TestCase#process now expects the HTTP method as second argument: process(action, http_method, params, session, flash)", callstack)
607
+ args.unshift(http_method)
608
+ http_method = args.last.is_a?(String) ? args.last : "GET"
609
+ end
610
+
611
+ [http_method, args]
612
+ end
520
613
 
521
614
  def build_request_uri(action, parameters)
522
615
  unless @request.env["PATH_INFO"]
@@ -525,7 +618,7 @@ module ActionController
525
618
  :only_path => true,
526
619
  :action => action,
527
620
  :relative_url_root => nil,
528
- :_path_segments => @request.symbolized_path_parameters)
621
+ :_recall => @request.symbolized_path_parameters)
529
622
 
530
623
  url, query_string = @routes.url_for(options).split("?", 2)
531
624
 
@@ -537,8 +630,7 @@ module ActionController
537
630
 
538
631
  def html_format?(parameters)
539
632
  return true unless parameters.is_a?(Hash)
540
- format = Mime[parameters[:format]]
541
- format.nil? || format.html?
633
+ Mime.fetch(parameters[:format]) { Mime['html'] }.html?
542
634
  end
543
635
  end
544
636
 
@@ -549,7 +641,7 @@ module ActionController
549
641
  #
550
642
  # The exception is stored in the exception accessor for further inspection.
551
643
  module RaiseActionExceptions
552
- def self.included(base)
644
+ def self.included(base) #:nodoc:
553
645
  unless base.method_defined?(:exception) && base.method_defined?(:exception=)
554
646
  base.class_eval do
555
647
  attr_accessor :exception