actionpack 3.2.22.5 → 5.2.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (271) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +279 -603
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +13 -297
  5. data/lib/abstract_controller/asset_paths.rb +4 -2
  6. data/lib/abstract_controller/base.rb +82 -52
  7. data/lib/abstract_controller/caching/fragments.rb +166 -0
  8. data/lib/abstract_controller/caching.rb +66 -0
  9. data/lib/abstract_controller/callbacks.rb +117 -103
  10. data/lib/abstract_controller/collector.rb +18 -7
  11. data/lib/abstract_controller/error.rb +6 -0
  12. data/lib/abstract_controller/helpers.rb +65 -38
  13. data/lib/abstract_controller/logger.rb +3 -2
  14. data/lib/abstract_controller/railties/routes_helpers.rb +5 -3
  15. data/lib/abstract_controller/rendering.rb +77 -129
  16. data/lib/abstract_controller/translation.rb +21 -3
  17. data/lib/abstract_controller/url_for.rb +9 -7
  18. data/lib/abstract_controller.rb +12 -13
  19. data/lib/action_controller/api/api_rendering.rb +16 -0
  20. data/lib/action_controller/api.rb +149 -0
  21. data/lib/action_controller/base.rb +81 -40
  22. data/lib/action_controller/caching.rb +22 -62
  23. data/lib/action_controller/form_builder.rb +50 -0
  24. data/lib/action_controller/log_subscriber.rb +30 -18
  25. data/lib/action_controller/metal/basic_implicit_render.rb +13 -0
  26. data/lib/action_controller/metal/conditional_get.rb +190 -47
  27. data/lib/action_controller/metal/content_security_policy.rb +52 -0
  28. data/lib/action_controller/metal/cookies.rb +3 -3
  29. data/lib/action_controller/metal/data_streaming.rb +40 -65
  30. data/lib/action_controller/metal/etag_with_flash.rb +18 -0
  31. data/lib/action_controller/metal/etag_with_template_digest.rb +57 -0
  32. data/lib/action_controller/metal/exceptions.rb +19 -12
  33. data/lib/action_controller/metal/flash.rb +42 -9
  34. data/lib/action_controller/metal/force_ssl.rb +79 -19
  35. data/lib/action_controller/metal/head.rb +35 -10
  36. data/lib/action_controller/metal/helpers.rb +31 -21
  37. data/lib/action_controller/metal/http_authentication.rb +182 -134
  38. data/lib/action_controller/metal/implicit_render.rb +62 -8
  39. data/lib/action_controller/metal/instrumentation.rb +28 -26
  40. data/lib/action_controller/metal/live.rb +312 -0
  41. data/lib/action_controller/metal/mime_responds.rb +159 -163
  42. data/lib/action_controller/metal/parameter_encoding.rb +51 -0
  43. data/lib/action_controller/metal/params_wrapper.rb +146 -93
  44. data/lib/action_controller/metal/redirecting.rb +80 -56
  45. data/lib/action_controller/metal/renderers.rb +119 -47
  46. data/lib/action_controller/metal/rendering.rb +89 -32
  47. data/lib/action_controller/metal/request_forgery_protection.rb +373 -41
  48. data/lib/action_controller/metal/rescue.rb +9 -16
  49. data/lib/action_controller/metal/streaming.rb +39 -45
  50. data/lib/action_controller/metal/strong_parameters.rb +1086 -0
  51. data/lib/action_controller/metal/testing.rb +8 -29
  52. data/lib/action_controller/metal/url_for.rb +43 -32
  53. data/lib/action_controller/metal.rb +112 -106
  54. data/lib/action_controller/railtie.rb +56 -18
  55. data/lib/action_controller/railties/helpers.rb +24 -0
  56. data/lib/action_controller/renderer.rb +117 -0
  57. data/lib/action_controller/template_assertions.rb +11 -0
  58. data/lib/action_controller/test_case.rb +402 -347
  59. data/lib/action_controller.rb +31 -30
  60. data/lib/action_dispatch/http/cache.rb +133 -34
  61. data/lib/action_dispatch/http/content_security_policy.rb +272 -0
  62. data/lib/action_dispatch/http/filter_parameters.rb +40 -24
  63. data/lib/action_dispatch/http/filter_redirect.rb +37 -0
  64. data/lib/action_dispatch/http/headers.rb +117 -16
  65. data/lib/action_dispatch/http/mime_negotiation.rb +98 -33
  66. data/lib/action_dispatch/http/mime_type.rb +198 -146
  67. data/lib/action_dispatch/http/mime_types.rb +22 -7
  68. data/lib/action_dispatch/http/parameter_filter.rb +61 -49
  69. data/lib/action_dispatch/http/parameters.rb +94 -51
  70. data/lib/action_dispatch/http/rack_cache.rb +4 -3
  71. data/lib/action_dispatch/http/request.rb +262 -117
  72. data/lib/action_dispatch/http/response.rb +400 -86
  73. data/lib/action_dispatch/http/upload.rb +66 -29
  74. data/lib/action_dispatch/http/url.rb +232 -60
  75. data/lib/action_dispatch/journey/formatter.rb +189 -0
  76. data/lib/action_dispatch/journey/gtg/builder.rb +164 -0
  77. data/lib/action_dispatch/journey/gtg/simulator.rb +41 -0
  78. data/lib/action_dispatch/journey/gtg/transition_table.rb +158 -0
  79. data/lib/action_dispatch/journey/nfa/builder.rb +78 -0
  80. data/lib/action_dispatch/journey/nfa/dot.rb +36 -0
  81. data/lib/action_dispatch/journey/nfa/simulator.rb +49 -0
  82. data/lib/action_dispatch/journey/nfa/transition_table.rb +120 -0
  83. data/lib/action_dispatch/journey/nodes/node.rb +140 -0
  84. data/lib/action_dispatch/journey/parser.rb +199 -0
  85. data/lib/action_dispatch/journey/parser.y +50 -0
  86. data/lib/action_dispatch/journey/parser_extras.rb +31 -0
  87. data/lib/action_dispatch/journey/path/pattern.rb +199 -0
  88. data/lib/action_dispatch/journey/route.rb +203 -0
  89. data/lib/action_dispatch/journey/router/utils.rb +102 -0
  90. data/lib/action_dispatch/journey/router.rb +156 -0
  91. data/lib/action_dispatch/journey/routes.rb +82 -0
  92. data/lib/action_dispatch/journey/scanner.rb +64 -0
  93. data/lib/action_dispatch/journey/visitors.rb +268 -0
  94. data/lib/action_dispatch/journey/visualizer/fsm.css +30 -0
  95. data/lib/action_dispatch/journey/visualizer/fsm.js +134 -0
  96. data/lib/action_dispatch/journey/visualizer/index.html.erb +52 -0
  97. data/lib/action_dispatch/journey.rb +7 -0
  98. data/lib/action_dispatch/middleware/callbacks.rb +17 -13
  99. data/lib/action_dispatch/middleware/cookies.rb +494 -162
  100. data/lib/action_dispatch/middleware/debug_exceptions.rb +176 -53
  101. data/lib/action_dispatch/middleware/debug_locks.rb +124 -0
  102. data/lib/action_dispatch/middleware/exception_wrapper.rb +103 -38
  103. data/lib/action_dispatch/middleware/executor.rb +21 -0
  104. data/lib/action_dispatch/middleware/flash.rb +128 -91
  105. data/lib/action_dispatch/middleware/public_exceptions.rb +43 -16
  106. data/lib/action_dispatch/middleware/reloader.rb +6 -83
  107. data/lib/action_dispatch/middleware/remote_ip.rb +151 -49
  108. data/lib/action_dispatch/middleware/request_id.rb +19 -15
  109. data/lib/action_dispatch/middleware/session/abstract_store.rb +38 -34
  110. data/lib/action_dispatch/middleware/session/cache_store.rb +14 -9
  111. data/lib/action_dispatch/middleware/session/cookie_store.rb +94 -44
  112. data/lib/action_dispatch/middleware/session/mem_cache_store.rb +15 -4
  113. data/lib/action_dispatch/middleware/show_exceptions.rb +36 -61
  114. data/lib/action_dispatch/middleware/ssl.rb +150 -0
  115. data/lib/action_dispatch/middleware/stack.rb +33 -41
  116. data/lib/action_dispatch/middleware/static.rb +92 -48
  117. data/lib/action_dispatch/middleware/templates/rescues/_request_and_response.html.erb +22 -0
  118. data/lib/action_dispatch/middleware/templates/rescues/_request_and_response.text.erb +23 -0
  119. data/lib/action_dispatch/middleware/templates/rescues/_source.html.erb +27 -0
  120. data/lib/action_dispatch/middleware/templates/rescues/_source.text.erb +8 -0
  121. data/lib/action_dispatch/middleware/templates/rescues/_trace.html.erb +52 -0
  122. data/lib/action_dispatch/middleware/templates/rescues/_trace.text.erb +9 -0
  123. data/lib/action_dispatch/middleware/templates/rescues/diagnostics.html.erb +16 -0
  124. data/lib/action_dispatch/middleware/templates/rescues/diagnostics.text.erb +9 -0
  125. data/lib/action_dispatch/middleware/templates/rescues/invalid_statement.html.erb +21 -0
  126. data/lib/action_dispatch/middleware/templates/rescues/invalid_statement.text.erb +13 -0
  127. data/lib/action_dispatch/middleware/templates/rescues/layout.erb +134 -5
  128. data/lib/action_dispatch/middleware/templates/rescues/missing_template.html.erb +11 -0
  129. data/lib/action_dispatch/middleware/templates/rescues/missing_template.text.erb +3 -0
  130. data/lib/action_dispatch/middleware/templates/rescues/routing_error.html.erb +32 -0
  131. data/lib/action_dispatch/middleware/templates/rescues/routing_error.text.erb +11 -0
  132. data/lib/action_dispatch/middleware/templates/rescues/template_error.html.erb +20 -0
  133. data/lib/action_dispatch/middleware/templates/rescues/template_error.text.erb +7 -0
  134. data/lib/action_dispatch/middleware/templates/rescues/unknown_action.html.erb +6 -0
  135. data/lib/action_dispatch/middleware/templates/rescues/unknown_action.text.erb +3 -0
  136. data/lib/action_dispatch/middleware/templates/routes/_route.html.erb +16 -0
  137. data/lib/action_dispatch/middleware/templates/routes/_table.html.erb +200 -0
  138. data/lib/action_dispatch/railtie.rb +29 -8
  139. data/lib/action_dispatch/request/session.rb +234 -0
  140. data/lib/action_dispatch/request/utils.rb +78 -0
  141. data/lib/action_dispatch/routing/endpoint.rb +17 -0
  142. data/lib/action_dispatch/routing/inspector.rb +225 -0
  143. data/lib/action_dispatch/routing/mapper.rb +1329 -582
  144. data/lib/action_dispatch/routing/polymorphic_routes.rb +237 -94
  145. data/lib/action_dispatch/routing/redirection.rb +120 -50
  146. data/lib/action_dispatch/routing/route_set.rb +545 -322
  147. data/lib/action_dispatch/routing/routes_proxy.rb +37 -7
  148. data/lib/action_dispatch/routing/url_for.rb +103 -34
  149. data/lib/action_dispatch/routing.rb +66 -99
  150. data/lib/action_dispatch/system_test_case.rb +147 -0
  151. data/lib/action_dispatch/system_testing/browser.rb +49 -0
  152. data/lib/action_dispatch/system_testing/driver.rb +59 -0
  153. data/lib/action_dispatch/system_testing/server.rb +31 -0
  154. data/lib/action_dispatch/system_testing/test_helpers/screenshot_helper.rb +96 -0
  155. data/lib/action_dispatch/system_testing/test_helpers/setup_and_teardown.rb +31 -0
  156. data/lib/action_dispatch/system_testing/test_helpers/undef_methods.rb +26 -0
  157. data/lib/action_dispatch/testing/assertion_response.rb +47 -0
  158. data/lib/action_dispatch/testing/assertions/response.rb +53 -42
  159. data/lib/action_dispatch/testing/assertions/routing.rb +79 -74
  160. data/lib/action_dispatch/testing/assertions.rb +15 -9
  161. data/lib/action_dispatch/testing/integration.rb +361 -207
  162. data/lib/action_dispatch/testing/request_encoder.rb +55 -0
  163. data/lib/action_dispatch/testing/test_process.rb +28 -19
  164. data/lib/action_dispatch/testing/test_request.rb +30 -33
  165. data/lib/action_dispatch/testing/test_response.rb +35 -11
  166. data/lib/action_dispatch.rb +42 -32
  167. data/lib/action_pack/gem_version.rb +17 -0
  168. data/lib/action_pack/version.rb +7 -7
  169. data/lib/action_pack.rb +4 -2
  170. metadata +116 -175
  171. data/lib/abstract_controller/layouts.rb +0 -423
  172. data/lib/abstract_controller/view_paths.rb +0 -96
  173. data/lib/action_controller/caching/actions.rb +0 -185
  174. data/lib/action_controller/caching/fragments.rb +0 -127
  175. data/lib/action_controller/caching/pages.rb +0 -187
  176. data/lib/action_controller/caching/sweeping.rb +0 -97
  177. data/lib/action_controller/deprecated/integration_test.rb +0 -2
  178. data/lib/action_controller/deprecated/performance_test.rb +0 -1
  179. data/lib/action_controller/deprecated.rb +0 -3
  180. data/lib/action_controller/metal/compatibility.rb +0 -65
  181. data/lib/action_controller/metal/hide_actions.rb +0 -41
  182. data/lib/action_controller/metal/rack_delegation.rb +0 -26
  183. data/lib/action_controller/metal/responder.rb +0 -286
  184. data/lib/action_controller/metal/session_management.rb +0 -14
  185. data/lib/action_controller/middleware.rb +0 -39
  186. data/lib/action_controller/railties/paths.rb +0 -25
  187. data/lib/action_controller/record_identifier.rb +0 -85
  188. data/lib/action_controller/vendor/html-scanner/html/document.rb +0 -68
  189. data/lib/action_controller/vendor/html-scanner/html/node.rb +0 -532
  190. data/lib/action_controller/vendor/html-scanner/html/sanitizer.rb +0 -177
  191. data/lib/action_controller/vendor/html-scanner/html/selector.rb +0 -830
  192. data/lib/action_controller/vendor/html-scanner/html/tokenizer.rb +0 -107
  193. data/lib/action_controller/vendor/html-scanner/html/version.rb +0 -11
  194. data/lib/action_controller/vendor/html-scanner.rb +0 -20
  195. data/lib/action_dispatch/middleware/best_standards_support.rb +0 -30
  196. data/lib/action_dispatch/middleware/body_proxy.rb +0 -30
  197. data/lib/action_dispatch/middleware/head.rb +0 -18
  198. data/lib/action_dispatch/middleware/params_parser.rb +0 -75
  199. data/lib/action_dispatch/middleware/rescue.rb +0 -26
  200. data/lib/action_dispatch/middleware/templates/rescues/_request_and_response.erb +0 -31
  201. data/lib/action_dispatch/middleware/templates/rescues/_trace.erb +0 -26
  202. data/lib/action_dispatch/middleware/templates/rescues/diagnostics.erb +0 -10
  203. data/lib/action_dispatch/middleware/templates/rescues/missing_template.erb +0 -2
  204. data/lib/action_dispatch/middleware/templates/rescues/routing_error.erb +0 -15
  205. data/lib/action_dispatch/middleware/templates/rescues/template_error.erb +0 -17
  206. data/lib/action_dispatch/middleware/templates/rescues/unknown_action.erb +0 -2
  207. data/lib/action_dispatch/testing/assertions/dom.rb +0 -37
  208. data/lib/action_dispatch/testing/assertions/selector.rb +0 -435
  209. data/lib/action_dispatch/testing/assertions/tag.rb +0 -138
  210. data/lib/action_dispatch/testing/performance_test.rb +0 -10
  211. data/lib/action_view/asset_paths.rb +0 -142
  212. data/lib/action_view/base.rb +0 -220
  213. data/lib/action_view/buffers.rb +0 -43
  214. data/lib/action_view/context.rb +0 -36
  215. data/lib/action_view/flows.rb +0 -79
  216. data/lib/action_view/helpers/active_model_helper.rb +0 -50
  217. data/lib/action_view/helpers/asset_paths.rb +0 -7
  218. data/lib/action_view/helpers/asset_tag_helper.rb +0 -457
  219. data/lib/action_view/helpers/asset_tag_helpers/asset_include_tag.rb +0 -146
  220. data/lib/action_view/helpers/asset_tag_helpers/asset_paths.rb +0 -93
  221. data/lib/action_view/helpers/asset_tag_helpers/javascript_tag_helpers.rb +0 -193
  222. data/lib/action_view/helpers/asset_tag_helpers/stylesheet_tag_helpers.rb +0 -148
  223. data/lib/action_view/helpers/atom_feed_helper.rb +0 -200
  224. data/lib/action_view/helpers/cache_helper.rb +0 -64
  225. data/lib/action_view/helpers/capture_helper.rb +0 -203
  226. data/lib/action_view/helpers/controller_helper.rb +0 -25
  227. data/lib/action_view/helpers/csrf_helper.rb +0 -32
  228. data/lib/action_view/helpers/date_helper.rb +0 -1062
  229. data/lib/action_view/helpers/debug_helper.rb +0 -40
  230. data/lib/action_view/helpers/form_helper.rb +0 -1486
  231. data/lib/action_view/helpers/form_options_helper.rb +0 -658
  232. data/lib/action_view/helpers/form_tag_helper.rb +0 -685
  233. data/lib/action_view/helpers/javascript_helper.rb +0 -110
  234. data/lib/action_view/helpers/number_helper.rb +0 -622
  235. data/lib/action_view/helpers/output_safety_helper.rb +0 -38
  236. data/lib/action_view/helpers/record_tag_helper.rb +0 -111
  237. data/lib/action_view/helpers/rendering_helper.rb +0 -92
  238. data/lib/action_view/helpers/sanitize_helper.rb +0 -259
  239. data/lib/action_view/helpers/tag_helper.rb +0 -167
  240. data/lib/action_view/helpers/text_helper.rb +0 -426
  241. data/lib/action_view/helpers/translation_helper.rb +0 -91
  242. data/lib/action_view/helpers/url_helper.rb +0 -693
  243. data/lib/action_view/helpers.rb +0 -60
  244. data/lib/action_view/locale/en.yml +0 -160
  245. data/lib/action_view/log_subscriber.rb +0 -28
  246. data/lib/action_view/lookup_context.rb +0 -258
  247. data/lib/action_view/path_set.rb +0 -101
  248. data/lib/action_view/railtie.rb +0 -55
  249. data/lib/action_view/renderer/abstract_renderer.rb +0 -41
  250. data/lib/action_view/renderer/partial_renderer.rb +0 -415
  251. data/lib/action_view/renderer/renderer.rb +0 -61
  252. data/lib/action_view/renderer/streaming_template_renderer.rb +0 -106
  253. data/lib/action_view/renderer/template_renderer.rb +0 -95
  254. data/lib/action_view/template/error.rb +0 -128
  255. data/lib/action_view/template/handlers/builder.rb +0 -26
  256. data/lib/action_view/template/handlers/erb.rb +0 -125
  257. data/lib/action_view/template/handlers.rb +0 -50
  258. data/lib/action_view/template/resolver.rb +0 -298
  259. data/lib/action_view/template/text.rb +0 -30
  260. data/lib/action_view/template.rb +0 -337
  261. data/lib/action_view/test_case.rb +0 -246
  262. data/lib/action_view/testing/resolvers.rb +0 -49
  263. data/lib/action_view.rb +0 -84
  264. data/lib/sprockets/assets.rake +0 -99
  265. data/lib/sprockets/bootstrap.rb +0 -37
  266. data/lib/sprockets/compressors.rb +0 -83
  267. data/lib/sprockets/helpers/isolated_helper.rb +0 -13
  268. data/lib/sprockets/helpers/rails_helper.rb +0 -182
  269. data/lib/sprockets/helpers.rb +0 -6
  270. data/lib/sprockets/railtie.rb +0 -62
  271. data/lib/sprockets/static_compiler.rb +0 -56
@@ -1,10 +1,12 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActionDispatch
2
4
  module Routing
3
5
  # Polymorphic URL helpers are methods for smart resolution to a named route call when
4
6
  # given an Active Record model instance. They are to be used in combination with
5
7
  # ActionController::Resources.
6
8
  #
7
- # These methods are useful when you want to generate correct URL or path to a RESTful
9
+ # These methods are useful when you want to generate the correct URL or path to a RESTful
8
10
  # resource without having to know the exact type of the record in question.
9
11
  #
10
12
  # Nested resources and/or namespaces are also supported, as illustrated in the example:
@@ -32,7 +34,7 @@ module ActionDispatch
32
34
  # == Prefixed polymorphic helpers
33
35
  #
34
36
  # In addition to <tt>polymorphic_url</tt> and <tt>polymorphic_path</tt> methods, a
35
- # number of prefixed helpers are available as a shorthand to <tt>:action => "..."</tt>
37
+ # number of prefixed helpers are available as a shorthand to <tt>action: "..."</tt>
36
38
  # in options. Those are:
37
39
  #
38
40
  # * <tt>edit_polymorphic_url</tt>, <tt>edit_polymorphic_path</tt>
@@ -40,19 +42,17 @@ module ActionDispatch
40
42
  #
41
43
  # Example usage:
42
44
  #
43
- # edit_polymorphic_path(@post) # => "/posts/1/edit"
44
- # polymorphic_path(@post, :format => :pdf) # => "/posts/1.pdf"
45
- #
46
- # == Using with mounted engines
45
+ # edit_polymorphic_path(@post) # => "/posts/1/edit"
46
+ # polymorphic_path(@post, format: :pdf) # => "/posts/1.pdf"
47
47
  #
48
- # If you use mounted engine, there is a possibility that you will need to use
49
- # polymorphic_url pointing at engine's routes. To do that, just pass proxy used
50
- # to reach engine's routes as a first argument:
48
+ # == Usage with mounted engines
51
49
  #
52
- # For example:
50
+ # If you are using a mounted engine and you need to use a polymorphic_url
51
+ # pointing at the engine's routes, pass in the engine's route proxy as the first
52
+ # argument to the method. For example:
53
53
  #
54
- # polymorphic_url([blog, @post]) # it will call blog.post_path(@post)
55
- # form_for([blog, @post]) # => "/blog/posts/1
54
+ # polymorphic_url([blog, @post]) # calls blog.post_path(@post)
55
+ # form_for([blog, @post]) # => "/blog/posts/1"
56
56
  #
57
57
  module PolymorphicRoutes
58
58
  # Constructs a call to a named RESTful route for the given record and returns the
@@ -72,7 +72,18 @@ module ActionDispatch
72
72
  # * <tt>:routing_type</tt> - Allowed values are <tt>:path</tt> or <tt>:url</tt>.
73
73
  # Default is <tt>:url</tt>.
74
74
  #
75
- # ==== Examples
75
+ # Also includes all the options from <tt>url_for</tt>. These include such
76
+ # things as <tt>:anchor</tt> or <tt>:trailing_slash</tt>. Example usage
77
+ # is given below:
78
+ #
79
+ # polymorphic_url([blog, post], anchor: 'my_anchor')
80
+ # # => "http://example.com/blogs/1/posts/1#my_anchor"
81
+ # polymorphic_url([blog, post], anchor: 'my_anchor', script_name: "/my_app")
82
+ # # => "http://example.com/my_app/blogs/1/posts/1#my_anchor"
83
+ #
84
+ # For all of these options, see the documentation for {url_for}[rdoc-ref:ActionDispatch::Routing::UrlFor].
85
+ #
86
+ # ==== Functionality
76
87
  #
77
88
  # # an Article record
78
89
  # polymorphic_url(record) # same as article_url(record)
@@ -88,122 +99,254 @@ module ActionDispatch
88
99
  # polymorphic_url(Comment) # same as comments_url()
89
100
  #
90
101
  def polymorphic_url(record_or_hash_or_array, options = {})
91
- if record_or_hash_or_array.kind_of?(Array)
92
- record_or_hash_or_array = record_or_hash_or_array.compact
93
- if record_or_hash_or_array.first.is_a?(ActionDispatch::Routing::RoutesProxy)
94
- proxy = record_or_hash_or_array.shift
95
- end
96
- record_or_hash_or_array = record_or_hash_or_array[0] if record_or_hash_or_array.size == 1
102
+ if Hash === record_or_hash_or_array
103
+ options = record_or_hash_or_array.merge(options)
104
+ record = options.delete :id
105
+ return polymorphic_url record, options
97
106
  end
98
107
 
99
- record = extract_record(record_or_hash_or_array)
100
- record = convert_to_model(record)
101
-
102
- args = Array === record_or_hash_or_array ?
103
- record_or_hash_or_array.dup :
104
- [ record_or_hash_or_array ]
105
-
106
- inflection = if options[:action] && options[:action].to_s == "new"
107
- args.pop
108
- :singular
109
- elsif (record.respond_to?(:persisted?) && !record.persisted?)
110
- args.pop
111
- :plural
112
- elsif record.is_a?(Class)
113
- args.pop
114
- :plural
115
- else
116
- :singular
108
+ if mapping = polymorphic_mapping(record_or_hash_or_array)
109
+ return mapping.call(self, [record_or_hash_or_array, options], false)
117
110
  end
118
111
 
119
- args.delete_if {|arg| arg.is_a?(Symbol) || arg.is_a?(String)}
120
- named_route = build_named_route_call(record_or_hash_or_array, inflection, options)
112
+ opts = options.dup
113
+ action = opts.delete :action
114
+ type = opts.delete(:routing_type) || :url
121
115
 
122
- url_options = options.except(:action, :routing_type)
123
- unless url_options.empty?
124
- args.last.kind_of?(Hash) ? args.last.merge!(url_options) : args << url_options
125
- end
126
-
127
- args.collect! { |a| convert_to_model(a) }
128
-
129
- (proxy || self).send(named_route, *args)
116
+ HelperMethodBuilder.polymorphic_method self,
117
+ record_or_hash_or_array,
118
+ action,
119
+ type,
120
+ opts
130
121
  end
131
122
 
132
123
  # Returns the path component of a URL for the given record. It uses
133
- # <tt>polymorphic_url</tt> with <tt>:routing_type => :path</tt>.
124
+ # <tt>polymorphic_url</tt> with <tt>routing_type: :path</tt>.
134
125
  def polymorphic_path(record_or_hash_or_array, options = {})
135
- polymorphic_url(record_or_hash_or_array, options.merge(:routing_type => :path))
126
+ if Hash === record_or_hash_or_array
127
+ options = record_or_hash_or_array.merge(options)
128
+ record = options.delete :id
129
+ return polymorphic_path record, options
130
+ end
131
+
132
+ if mapping = polymorphic_mapping(record_or_hash_or_array)
133
+ return mapping.call(self, [record_or_hash_or_array, options], true)
134
+ end
135
+
136
+ opts = options.dup
137
+ action = opts.delete :action
138
+ type = :path
139
+
140
+ HelperMethodBuilder.polymorphic_method self,
141
+ record_or_hash_or_array,
142
+ action,
143
+ type,
144
+ opts
136
145
  end
137
146
 
138
147
  %w(edit new).each do |action|
139
148
  module_eval <<-EOT, __FILE__, __LINE__ + 1
140
- def #{action}_polymorphic_url(record_or_hash, options = {}) # def edit_polymorphic_url(record_or_hash, options = {})
141
- polymorphic_url( # polymorphic_url(
142
- record_or_hash, # record_or_hash,
143
- options.merge(:action => "#{action}")) # options.merge(:action => "edit"))
144
- end # end
145
- #
146
- def #{action}_polymorphic_path(record_or_hash, options = {}) # def edit_polymorphic_path(record_or_hash, options = {})
147
- polymorphic_url( # polymorphic_url(
148
- record_or_hash, # record_or_hash,
149
- options.merge(:action => "#{action}", :routing_type => :path)) # options.merge(:action => "edit", :routing_type => :path))
150
- end # end
149
+ def #{action}_polymorphic_url(record_or_hash, options = {})
150
+ polymorphic_url_for_action("#{action}", record_or_hash, options)
151
+ end
152
+
153
+ def #{action}_polymorphic_path(record_or_hash, options = {})
154
+ polymorphic_path_for_action("#{action}", record_or_hash, options)
155
+ end
151
156
  EOT
152
157
  end
153
158
 
154
159
  private
155
- def action_prefix(options)
156
- options[:action] ? "#{options[:action]}_" : ''
160
+
161
+ def polymorphic_url_for_action(action, record_or_hash, options)
162
+ polymorphic_url(record_or_hash, options.merge(action: action))
157
163
  end
158
164
 
159
- def convert_to_model(object)
160
- object.respond_to?(:to_model) ? object.to_model : object
165
+ def polymorphic_path_for_action(action, record_or_hash, options)
166
+ polymorphic_path(record_or_hash, options.merge(action: action))
161
167
  end
162
168
 
163
- def routing_type(options)
164
- options[:routing_type] || :url
169
+ def polymorphic_mapping(record)
170
+ if record.respond_to?(:to_model)
171
+ _routes.polymorphic_mappings[record.to_model.model_name.name]
172
+ else
173
+ _routes.polymorphic_mappings[record.class.name]
174
+ end
165
175
  end
166
176
 
167
- def build_named_route_call(records, inflection, options = {})
168
- if records.is_a?(Array)
169
- record = records.pop
170
- route = records.map do |parent|
171
- if parent.is_a?(Symbol) || parent.is_a?(String)
172
- parent
173
- else
174
- ActiveModel::Naming.singular_route_key(parent)
177
+ class HelperMethodBuilder # :nodoc:
178
+ CACHE = { "path" => {}, "url" => {} }
179
+
180
+ def self.get(action, type)
181
+ type = type.to_s
182
+ CACHE[type].fetch(action) { build action, type }
183
+ end
184
+
185
+ def self.url; CACHE["url".freeze][nil]; end
186
+ def self.path; CACHE["path".freeze][nil]; end
187
+
188
+ def self.build(action, type)
189
+ prefix = action ? "#{action}_" : ""
190
+ suffix = type
191
+ if action.to_s == "new"
192
+ HelperMethodBuilder.singular prefix, suffix
193
+ else
194
+ HelperMethodBuilder.plural prefix, suffix
195
+ end
196
+ end
197
+
198
+ def self.singular(prefix, suffix)
199
+ new(->(name) { name.singular_route_key }, prefix, suffix)
200
+ end
201
+
202
+ def self.plural(prefix, suffix)
203
+ new(->(name) { name.route_key }, prefix, suffix)
204
+ end
205
+
206
+ def self.polymorphic_method(recipient, record_or_hash_or_array, action, type, options)
207
+ builder = get action, type
208
+
209
+ case record_or_hash_or_array
210
+ when Array
211
+ record_or_hash_or_array = record_or_hash_or_array.compact
212
+ if record_or_hash_or_array.empty?
213
+ raise ArgumentError, "Nil location provided. Can't build URI."
175
214
  end
215
+ if record_or_hash_or_array.first.is_a?(ActionDispatch::Routing::RoutesProxy)
216
+ recipient = record_or_hash_or_array.shift
217
+ end
218
+
219
+ method, args = builder.handle_list record_or_hash_or_array
220
+ when String, Symbol
221
+ method, args = builder.handle_string record_or_hash_or_array
222
+ when Class
223
+ method, args = builder.handle_class record_or_hash_or_array
224
+
225
+ when nil
226
+ raise ArgumentError, "Nil location provided. Can't build URI."
227
+ else
228
+ method, args = builder.handle_model record_or_hash_or_array
176
229
  end
177
- else
178
- record = extract_record(records)
179
- route = []
230
+
231
+ if options.empty?
232
+ recipient.send(method, *args)
233
+ else
234
+ recipient.send(method, *args, options)
235
+ end
236
+ end
237
+
238
+ attr_reader :suffix, :prefix
239
+
240
+ def initialize(key_strategy, prefix, suffix)
241
+ @key_strategy = key_strategy
242
+ @prefix = prefix
243
+ @suffix = suffix
244
+ end
245
+
246
+ def handle_string(record)
247
+ [get_method_for_string(record), []]
180
248
  end
181
249
 
182
- if record.is_a?(Symbol) || record.is_a?(String)
183
- route << record
184
- elsif record
185
- if inflection == :singular
186
- route << ActiveModel::Naming.singular_route_key(record)
250
+ def handle_string_call(target, str)
251
+ target.send get_method_for_string str
252
+ end
253
+
254
+ def handle_class(klass)
255
+ [get_method_for_class(klass), []]
256
+ end
257
+
258
+ def handle_class_call(target, klass)
259
+ target.send get_method_for_class klass
260
+ end
261
+
262
+ def handle_model(record)
263
+ args = []
264
+
265
+ model = record.to_model
266
+ named_route = if model.persisted?
267
+ args << model
268
+ get_method_for_string model.model_name.singular_route_key
187
269
  else
188
- route << ActiveModel::Naming.route_key(record)
270
+ get_method_for_class model
271
+ end
272
+
273
+ [named_route, args]
274
+ end
275
+
276
+ def handle_model_call(target, record)
277
+ if mapping = polymorphic_mapping(target, record)
278
+ mapping.call(target, [record], suffix == "path")
279
+ else
280
+ method, args = handle_model(record)
281
+ target.send(method, *args)
189
282
  end
190
- else
191
- raise ArgumentError, "Nil location provided. Can't build URI."
192
283
  end
193
284
 
194
- route << routing_type(options)
285
+ def handle_list(list)
286
+ record_list = list.dup
287
+ record = record_list.pop
195
288
 
196
- action_prefix(options) + route.join("_")
197
- end
289
+ args = []
198
290
 
199
- def extract_record(record_or_hash_or_array)
200
- case record_or_hash_or_array
201
- when Array; record_or_hash_or_array.last
202
- when Hash; record_or_hash_or_array[:id]
203
- else record_or_hash_or_array
291
+ route = record_list.map { |parent|
292
+ case parent
293
+ when Symbol, String
294
+ parent.to_s
295
+ when Class
296
+ args << parent
297
+ parent.model_name.singular_route_key
298
+ else
299
+ args << parent.to_model
300
+ parent.to_model.model_name.singular_route_key
301
+ end
302
+ }
303
+
304
+ route <<
305
+ case record
306
+ when Symbol, String
307
+ record.to_s
308
+ when Class
309
+ @key_strategy.call record.model_name
310
+ else
311
+ model = record.to_model
312
+ if model.persisted?
313
+ args << model
314
+ model.model_name.singular_route_key
315
+ else
316
+ @key_strategy.call model.model_name
317
+ end
318
+ end
319
+
320
+ route << suffix
321
+
322
+ named_route = prefix + route.join("_")
323
+ [named_route, args]
204
324
  end
325
+
326
+ private
327
+
328
+ def polymorphic_mapping(target, record)
329
+ if record.respond_to?(:to_model)
330
+ target._routes.polymorphic_mappings[record.to_model.model_name.name]
331
+ else
332
+ target._routes.polymorphic_mappings[record.class.name]
333
+ end
334
+ end
335
+
336
+ def get_method_for_class(klass)
337
+ name = @key_strategy.call klass.model_name
338
+ get_method_for_string name
339
+ end
340
+
341
+ def get_method_for_string(str)
342
+ "#{prefix}#{str}_#{suffix}"
343
+ end
344
+
345
+ [nil, "new", "edit"].each do |action|
346
+ CACHE["url"][action] = build action, "url"
347
+ CACHE["path"][action] = build action, "path"
348
+ end
205
349
  end
206
350
  end
207
351
  end
208
352
  end
209
-
@@ -1,10 +1,15 @@
1
- require 'action_dispatch/http/request'
2
- require 'active_support/core_ext/uri'
3
- require 'rack/utils'
1
+ # frozen_string_literal: true
2
+
3
+ require "action_dispatch/http/request"
4
+ require "active_support/core_ext/uri"
5
+ require "active_support/core_ext/array/extract_options"
6
+ require "rack/utils"
7
+ require "action_controller/metal/exceptions"
8
+ require "action_dispatch/routing/endpoint"
4
9
 
5
10
  module ActionDispatch
6
11
  module Routing
7
- class Redirect # :nodoc:
12
+ class Redirect < Endpoint # :nodoc:
8
13
  attr_reader :status, :block
9
14
 
10
15
  def initialize(status, block)
@@ -12,20 +17,35 @@ module ActionDispatch
12
17
  @block = block
13
18
  end
14
19
 
20
+ def redirect?; true; end
21
+
15
22
  def call(env)
16
- req = Request.new(env)
23
+ serve Request.new env
24
+ end
25
+
26
+ def serve(req)
27
+ uri = URI.parse(path(req.path_parameters, req))
28
+
29
+ unless uri.host
30
+ if relative_path?(uri.path)
31
+ uri.path = "#{req.script_name}/#{uri.path}"
32
+ elsif uri.path.empty?
33
+ uri.path = req.script_name.empty? ? "/" : req.script_name
34
+ end
35
+ end
17
36
 
18
- uri = URI.parse(path(req.symbolized_path_parameters, req))
19
37
  uri.scheme ||= req.scheme
20
38
  uri.host ||= req.host
21
39
  uri.port ||= req.port unless req.standard_port?
22
40
 
23
- body = %(<html><body>You are being <a href="#{ERB::Util.h(uri.to_s)}">redirected</a>.</body></html>)
41
+ req.commit_flash
42
+
43
+ body = %(<html><body>You are being <a href="#{ERB::Util.unwrapped_html_escape(uri.to_s)}">redirected</a>.</body></html>)
24
44
 
25
45
  headers = {
26
- 'Location' => uri.to_s,
27
- 'Content-Type' => 'text/html',
28
- 'Content-Length' => body.length.to_s
46
+ "Location" => uri.to_s,
47
+ "Content-Type" => "text/html",
48
+ "Content-Length" => body.length.to_s
29
49
  }
30
50
 
31
51
  [ status, headers, [body] ]
@@ -34,6 +54,52 @@ module ActionDispatch
34
54
  def path(params, request)
35
55
  block.call params, request
36
56
  end
57
+
58
+ def inspect
59
+ "redirect(#{status})"
60
+ end
61
+
62
+ private
63
+ def relative_path?(path)
64
+ path && !path.empty? && path[0] != "/"
65
+ end
66
+
67
+ def escape(params)
68
+ Hash[params.map { |k, v| [k, Rack::Utils.escape(v)] }]
69
+ end
70
+
71
+ def escape_fragment(params)
72
+ Hash[params.map { |k, v| [k, Journey::Router::Utils.escape_fragment(v)] }]
73
+ end
74
+
75
+ def escape_path(params)
76
+ Hash[params.map { |k, v| [k, Journey::Router::Utils.escape_path(v)] }]
77
+ end
78
+ end
79
+
80
+ class PathRedirect < Redirect
81
+ URL_PARTS = /\A([^?]+)?(\?[^#]+)?(#.+)?\z/
82
+
83
+ def path(params, request)
84
+ if block.match(URL_PARTS)
85
+ path = interpolation_required?($1, params) ? $1 % escape_path(params) : $1
86
+ query = interpolation_required?($2, params) ? $2 % escape(params) : $2
87
+ fragment = interpolation_required?($3, params) ? $3 % escape_fragment(params) : $3
88
+
89
+ "#{path}#{query}#{fragment}"
90
+ else
91
+ interpolation_required?(block, params) ? block % escape(params) : block
92
+ end
93
+ end
94
+
95
+ def inspect
96
+ "redirect(#{status}, #{block})"
97
+ end
98
+
99
+ private
100
+ def interpolation_required?(string, params)
101
+ !params.empty? && string && string.match(/%\{\w*\}/)
102
+ end
37
103
  end
38
104
 
39
105
  class OptionRedirect < Redirect # :nodoc:
@@ -41,35 +107,50 @@ module ActionDispatch
41
107
 
42
108
  def path(params, request)
43
109
  url_options = {
44
- :protocol => request.protocol,
45
- :host => request.host,
46
- :port => request.optional_port,
47
- :path => request.path,
48
- :params => request.query_parameters
49
- }.merge options
110
+ protocol: request.protocol,
111
+ host: request.host,
112
+ port: request.optional_port,
113
+ path: request.path,
114
+ params: request.query_parameters
115
+ }.merge! options
50
116
 
51
117
  if !params.empty? && url_options[:path].match(/%\{\w*\}/)
52
118
  url_options[:path] = (url_options[:path] % escape_path(params))
53
119
  end
54
120
 
121
+ unless options[:host] || options[:domain]
122
+ if relative_path?(url_options[:path])
123
+ url_options[:path] = "/#{url_options[:path]}"
124
+ url_options[:script_name] = request.script_name
125
+ elsif url_options[:path].empty?
126
+ url_options[:path] = request.script_name.empty? ? "/" : ""
127
+ url_options[:script_name] = request.script_name
128
+ end
129
+ end
130
+
55
131
  ActionDispatch::Http::URL.url_for url_options
56
132
  end
57
133
 
58
- private
59
- def escape_path(params)
60
- Hash[params.map{ |k,v| [k, URI.parser.escape(v)] }]
61
- end
134
+ def inspect
135
+ "redirect(#{status}, #{options.map { |k, v| "#{k}: #{v}" }.join(', ')})"
136
+ end
62
137
  end
63
138
 
64
139
  module Redirection
65
-
66
140
  # Redirect any path to another path:
67
141
  #
68
- # match "/stories" => redirect("/posts")
142
+ # get "/stories" => redirect("/posts")
143
+ #
144
+ # This will redirect the user, while ignoring certain parts of the request, including query string, etc.
145
+ # <tt>/stories</tt>, <tt>/stories?foo=bar</tt>, etc all redirect to <tt>/posts</tt>.
69
146
  #
70
147
  # You can also use interpolation in the supplied redirect argument:
71
148
  #
72
- # match 'docs/:article', :to => redirect('/wiki/%{article}')
149
+ # get 'docs/:article', to: redirect('/wiki/%{article}')
150
+ #
151
+ # Note that if you return a path without a leading slash then the URL is prefixed with the
152
+ # current SCRIPT_NAME environment variable. This is typically '/' but may be different in
153
+ # a mounted engine or where the application is deployed to a subdirectory of a website.
73
154
  #
74
155
  # Alternatively you can use one of the other syntaxes:
75
156
  #
@@ -78,54 +159,43 @@ module ActionDispatch
78
159
  # params, depending of how many arguments your block accepts. A string is required as a
79
160
  # return value.
80
161
  #
81
- # match 'jokes/:number', :to => redirect { |params, request|
162
+ # get 'jokes/:number', to: redirect { |params, request|
82
163
  # path = (params[:number].to_i.even? ? "wheres-the-beef" : "i-love-lamp")
83
164
  # "http://#{request.host_with_port}/#{path}"
84
165
  # }
85
166
  #
86
- # The options version of redirect allows you to supply only the parts of the url which need
167
+ # Note that the +do end+ syntax for the redirect block wouldn't work, as Ruby would pass
168
+ # the block to +get+ instead of +redirect+. Use <tt>{ ... }</tt> instead.
169
+ #
170
+ # The options version of redirect allows you to supply only the parts of the URL which need
87
171
  # to change, it also supports interpolation of the path similar to the first example.
88
172
  #
89
- # match 'stores/:name', :to => redirect(:subdomain => 'stores', :path => '/%{name}')
90
- # match 'stores/:name(*all)', :to => redirect(:subdomain => 'stores', :path => '/%{name}%{all}')
173
+ # get 'stores/:name', to: redirect(subdomain: 'stores', path: '/%{name}')
174
+ # get 'stores/:name(*all)', to: redirect(subdomain: 'stores', path: '/%{name}%{all}')
175
+ # get '/stories', to: redirect(path: '/posts')
176
+ #
177
+ # This will redirect the user, while changing only the specified parts of the request,
178
+ # for example the +path+ option in the last example.
179
+ # <tt>/stories</tt>, <tt>/stories?foo=bar</tt>, redirect to <tt>/posts</tt> and <tt>/posts?foo=bar</tt> respectively.
91
180
  #
92
181
  # Finally, an object which responds to call can be supplied to redirect, allowing you to reuse
93
182
  # common redirect routes. The call method must accept two arguments, params and request, and return
94
183
  # a string.
95
184
  #
96
- # match 'accounts/:name' => redirect(SubdomainRedirector.new('api'))
185
+ # get 'accounts/:name' => redirect(SubdomainRedirector.new('api'))
97
186
  #
98
187
  def redirect(*args, &block)
99
- options = args.last.is_a?(Hash) ? args.pop : {}
188
+ options = args.extract_options!
100
189
  status = options.delete(:status) || 301
190
+ path = args.shift
101
191
 
102
192
  return OptionRedirect.new(status, options) if options.any?
103
-
104
- path = args.shift
105
-
106
- block = lambda { |params, request|
107
- (params.empty? || !path.match(/%\{\w*\}/)) ? path : (path % escape(params))
108
- } if String === path
193
+ return PathRedirect.new(status, path) if String === path
109
194
 
110
195
  block = path if path.respond_to? :call
111
-
112
- # :FIXME: remove in Rails 4.0
113
- if block && block.respond_to?(:arity) && block.arity < 2
114
- msg = "redirect blocks with arity of #{block.arity} are deprecated. Your block must take 2 parameters: the environment, and a request object"
115
- ActiveSupport::Deprecation.warn msg
116
- deprecated_block = block
117
- block = lambda { |params, _| deprecated_block.call(params) }
118
- end
119
-
120
196
  raise ArgumentError, "redirection argument not supported" unless block
121
-
122
197
  Redirect.new status, block
123
198
  end
124
-
125
- private
126
- def escape(params)
127
- Hash[params.map{ |k,v| [k, Rack::Utils.escape(v)] }]
128
- end
129
199
  end
130
200
  end
131
201
  end