actionpack 3.2.19 → 4.2.11.3

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 (244) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +412 -503
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +11 -294
  5. data/lib/abstract_controller/asset_paths.rb +2 -2
  6. data/lib/abstract_controller/base.rb +52 -18
  7. data/lib/abstract_controller/callbacks.rb +87 -89
  8. data/lib/abstract_controller/collector.rb +17 -3
  9. data/lib/abstract_controller/helpers.rb +41 -14
  10. data/lib/abstract_controller/logger.rb +1 -2
  11. data/lib/abstract_controller/railties/routes_helpers.rb +3 -3
  12. data/lib/abstract_controller/rendering.rb +65 -118
  13. data/lib/abstract_controller/translation.rb +16 -1
  14. data/lib/abstract_controller/url_for.rb +7 -7
  15. data/lib/abstract_controller.rb +2 -10
  16. data/lib/action_controller/base.rb +61 -28
  17. data/lib/action_controller/caching/fragments.rb +30 -54
  18. data/lib/action_controller/caching.rb +38 -35
  19. data/lib/action_controller/log_subscriber.rb +35 -18
  20. data/lib/action_controller/metal/conditional_get.rb +103 -34
  21. data/lib/action_controller/metal/data_streaming.rb +20 -26
  22. data/lib/action_controller/metal/etag_with_template_digest.rb +50 -0
  23. data/lib/action_controller/metal/exceptions.rb +19 -6
  24. data/lib/action_controller/metal/flash.rb +41 -9
  25. data/lib/action_controller/metal/force_ssl.rb +70 -12
  26. data/lib/action_controller/metal/head.rb +30 -7
  27. data/lib/action_controller/metal/helpers.rb +11 -11
  28. data/lib/action_controller/metal/hide_actions.rb +0 -1
  29. data/lib/action_controller/metal/http_authentication.rb +140 -94
  30. data/lib/action_controller/metal/implicit_render.rb +1 -1
  31. data/lib/action_controller/metal/instrumentation.rb +11 -7
  32. data/lib/action_controller/metal/live.rb +328 -0
  33. data/lib/action_controller/metal/mime_responds.rb +161 -152
  34. data/lib/action_controller/metal/params_wrapper.rb +126 -81
  35. data/lib/action_controller/metal/rack_delegation.rb +10 -4
  36. data/lib/action_controller/metal/redirecting.rb +44 -41
  37. data/lib/action_controller/metal/renderers.rb +48 -19
  38. data/lib/action_controller/metal/rendering.rb +46 -11
  39. data/lib/action_controller/metal/request_forgery_protection.rb +250 -29
  40. data/lib/action_controller/metal/streaming.rb +30 -38
  41. data/lib/action_controller/metal/strong_parameters.rb +669 -0
  42. data/lib/action_controller/metal/testing.rb +12 -18
  43. data/lib/action_controller/metal/url_for.rb +31 -29
  44. data/lib/action_controller/metal.rb +31 -40
  45. data/lib/action_controller/model_naming.rb +12 -0
  46. data/lib/action_controller/railtie.rb +38 -18
  47. data/lib/action_controller/railties/helpers.rb +22 -0
  48. data/lib/action_controller/test_case.rb +359 -173
  49. data/lib/action_controller.rb +9 -16
  50. data/lib/action_dispatch/http/cache.rb +64 -11
  51. data/lib/action_dispatch/http/filter_parameters.rb +20 -10
  52. data/lib/action_dispatch/http/filter_redirect.rb +38 -0
  53. data/lib/action_dispatch/http/headers.rb +85 -17
  54. data/lib/action_dispatch/http/mime_negotiation.rb +55 -5
  55. data/lib/action_dispatch/http/mime_type.rb +167 -114
  56. data/lib/action_dispatch/http/mime_types.rb +2 -1
  57. data/lib/action_dispatch/http/parameter_filter.rb +44 -46
  58. data/lib/action_dispatch/http/parameters.rb +30 -46
  59. data/lib/action_dispatch/http/rack_cache.rb +2 -3
  60. data/lib/action_dispatch/http/request.rb +108 -45
  61. data/lib/action_dispatch/http/response.rb +247 -48
  62. data/lib/action_dispatch/http/upload.rb +60 -29
  63. data/lib/action_dispatch/http/url.rb +135 -45
  64. data/lib/action_dispatch/journey/backwards.rb +5 -0
  65. data/lib/action_dispatch/journey/formatter.rb +166 -0
  66. data/lib/action_dispatch/journey/gtg/builder.rb +162 -0
  67. data/lib/action_dispatch/journey/gtg/simulator.rb +47 -0
  68. data/lib/action_dispatch/journey/gtg/transition_table.rb +157 -0
  69. data/lib/action_dispatch/journey/nfa/builder.rb +76 -0
  70. data/lib/action_dispatch/journey/nfa/dot.rb +36 -0
  71. data/lib/action_dispatch/journey/nfa/simulator.rb +47 -0
  72. data/lib/action_dispatch/journey/nfa/transition_table.rb +163 -0
  73. data/lib/action_dispatch/journey/nodes/node.rb +128 -0
  74. data/lib/action_dispatch/journey/parser.rb +198 -0
  75. data/lib/action_dispatch/journey/parser.y +49 -0
  76. data/lib/action_dispatch/journey/parser_extras.rb +23 -0
  77. data/lib/action_dispatch/journey/path/pattern.rb +193 -0
  78. data/lib/action_dispatch/journey/route.rb +125 -0
  79. data/lib/action_dispatch/journey/router/strexp.rb +27 -0
  80. data/lib/action_dispatch/journey/router/utils.rb +93 -0
  81. data/lib/action_dispatch/journey/router.rb +144 -0
  82. data/lib/action_dispatch/journey/routes.rb +80 -0
  83. data/lib/action_dispatch/journey/scanner.rb +61 -0
  84. data/lib/action_dispatch/journey/visitors.rb +221 -0
  85. data/lib/action_dispatch/journey/visualizer/fsm.css +30 -0
  86. data/lib/action_dispatch/journey/visualizer/fsm.js +134 -0
  87. data/lib/action_dispatch/journey/visualizer/index.html.erb +52 -0
  88. data/lib/action_dispatch/journey.rb +5 -0
  89. data/lib/action_dispatch/middleware/callbacks.rb +16 -11
  90. data/lib/action_dispatch/middleware/cookies.rb +346 -125
  91. data/lib/action_dispatch/middleware/debug_exceptions.rb +52 -24
  92. data/lib/action_dispatch/middleware/exception_wrapper.rb +75 -9
  93. data/lib/action_dispatch/middleware/flash.rb +85 -72
  94. data/lib/action_dispatch/middleware/params_parser.rb +16 -31
  95. data/lib/action_dispatch/middleware/public_exceptions.rb +39 -14
  96. data/lib/action_dispatch/middleware/reloader.rb +16 -7
  97. data/lib/action_dispatch/middleware/remote_ip.rb +132 -40
  98. data/lib/action_dispatch/middleware/request_id.rb +3 -7
  99. data/lib/action_dispatch/middleware/session/abstract_store.rb +22 -20
  100. data/lib/action_dispatch/middleware/session/cache_store.rb +3 -3
  101. data/lib/action_dispatch/middleware/session/cookie_store.rb +84 -29
  102. data/lib/action_dispatch/middleware/session/mem_cache_store.rb +8 -3
  103. data/lib/action_dispatch/middleware/show_exceptions.rb +15 -44
  104. data/lib/action_dispatch/middleware/ssl.rb +72 -0
  105. data/lib/action_dispatch/middleware/stack.rb +6 -1
  106. data/lib/action_dispatch/middleware/static.rb +80 -23
  107. data/lib/action_dispatch/middleware/templates/rescues/_request_and_response.html.erb +34 -0
  108. data/lib/action_dispatch/middleware/templates/rescues/_request_and_response.text.erb +23 -0
  109. data/lib/action_dispatch/middleware/templates/rescues/_source.erb +27 -0
  110. data/lib/action_dispatch/middleware/templates/rescues/_trace.html.erb +52 -0
  111. data/lib/action_dispatch/middleware/templates/rescues/_trace.text.erb +9 -0
  112. data/lib/action_dispatch/middleware/templates/rescues/diagnostics.html.erb +16 -0
  113. data/lib/action_dispatch/middleware/templates/rescues/diagnostics.text.erb +9 -0
  114. data/lib/action_dispatch/middleware/templates/rescues/layout.erb +133 -5
  115. data/lib/action_dispatch/middleware/templates/rescues/missing_template.html.erb +11 -0
  116. data/lib/action_dispatch/middleware/templates/rescues/missing_template.text.erb +3 -0
  117. data/lib/action_dispatch/middleware/templates/rescues/routing_error.html.erb +32 -0
  118. data/lib/action_dispatch/middleware/templates/rescues/routing_error.text.erb +11 -0
  119. data/lib/action_dispatch/middleware/templates/rescues/template_error.html.erb +20 -0
  120. data/lib/action_dispatch/middleware/templates/rescues/template_error.text.erb +7 -0
  121. data/lib/action_dispatch/middleware/templates/rescues/unknown_action.html.erb +6 -0
  122. data/lib/action_dispatch/middleware/templates/rescues/unknown_action.text.erb +3 -0
  123. data/lib/action_dispatch/middleware/templates/routes/_route.html.erb +16 -0
  124. data/lib/action_dispatch/middleware/templates/routes/_table.html.erb +200 -0
  125. data/lib/action_dispatch/railtie.rb +19 -6
  126. data/lib/action_dispatch/request/session.rb +193 -0
  127. data/lib/action_dispatch/request/utils.rb +35 -0
  128. data/lib/action_dispatch/routing/endpoint.rb +10 -0
  129. data/lib/action_dispatch/routing/inspector.rb +234 -0
  130. data/lib/action_dispatch/routing/mapper.rb +897 -436
  131. data/lib/action_dispatch/routing/polymorphic_routes.rb +213 -92
  132. data/lib/action_dispatch/routing/redirection.rb +97 -37
  133. data/lib/action_dispatch/routing/route_set.rb +432 -239
  134. data/lib/action_dispatch/routing/routes_proxy.rb +7 -4
  135. data/lib/action_dispatch/routing/url_for.rb +63 -34
  136. data/lib/action_dispatch/routing.rb +57 -89
  137. data/lib/action_dispatch/testing/assertions/dom.rb +2 -36
  138. data/lib/action_dispatch/testing/assertions/response.rb +24 -38
  139. data/lib/action_dispatch/testing/assertions/routing.rb +55 -54
  140. data/lib/action_dispatch/testing/assertions/selector.rb +2 -434
  141. data/lib/action_dispatch/testing/assertions/tag.rb +2 -137
  142. data/lib/action_dispatch/testing/assertions.rb +11 -7
  143. data/lib/action_dispatch/testing/integration.rb +88 -72
  144. data/lib/action_dispatch/testing/test_process.rb +9 -6
  145. data/lib/action_dispatch/testing/test_request.rb +13 -9
  146. data/lib/action_dispatch/testing/test_response.rb +1 -5
  147. data/lib/action_dispatch.rb +24 -21
  148. data/lib/action_pack/gem_version.rb +15 -0
  149. data/lib/action_pack/version.rb +5 -7
  150. data/lib/action_pack.rb +1 -1
  151. metadata +181 -292
  152. data/lib/abstract_controller/layouts.rb +0 -423
  153. data/lib/abstract_controller/view_paths.rb +0 -96
  154. data/lib/action_controller/caching/actions.rb +0 -185
  155. data/lib/action_controller/caching/pages.rb +0 -187
  156. data/lib/action_controller/caching/sweeping.rb +0 -97
  157. data/lib/action_controller/deprecated/integration_test.rb +0 -2
  158. data/lib/action_controller/deprecated/performance_test.rb +0 -1
  159. data/lib/action_controller/deprecated.rb +0 -3
  160. data/lib/action_controller/metal/compatibility.rb +0 -65
  161. data/lib/action_controller/metal/responder.rb +0 -286
  162. data/lib/action_controller/metal/session_management.rb +0 -14
  163. data/lib/action_controller/railties/paths.rb +0 -25
  164. data/lib/action_controller/record_identifier.rb +0 -85
  165. data/lib/action_controller/vendor/html-scanner/html/document.rb +0 -68
  166. data/lib/action_controller/vendor/html-scanner/html/node.rb +0 -532
  167. data/lib/action_controller/vendor/html-scanner/html/sanitizer.rb +0 -177
  168. data/lib/action_controller/vendor/html-scanner/html/selector.rb +0 -830
  169. data/lib/action_controller/vendor/html-scanner/html/tokenizer.rb +0 -107
  170. data/lib/action_controller/vendor/html-scanner/html/version.rb +0 -11
  171. data/lib/action_controller/vendor/html-scanner.rb +0 -20
  172. data/lib/action_dispatch/middleware/best_standards_support.rb +0 -30
  173. data/lib/action_dispatch/middleware/body_proxy.rb +0 -30
  174. data/lib/action_dispatch/middleware/head.rb +0 -18
  175. data/lib/action_dispatch/middleware/rescue.rb +0 -26
  176. data/lib/action_dispatch/middleware/templates/rescues/_request_and_response.erb +0 -31
  177. data/lib/action_dispatch/middleware/templates/rescues/_trace.erb +0 -26
  178. data/lib/action_dispatch/middleware/templates/rescues/diagnostics.erb +0 -10
  179. data/lib/action_dispatch/middleware/templates/rescues/missing_template.erb +0 -2
  180. data/lib/action_dispatch/middleware/templates/rescues/routing_error.erb +0 -15
  181. data/lib/action_dispatch/middleware/templates/rescues/template_error.erb +0 -17
  182. data/lib/action_dispatch/middleware/templates/rescues/unknown_action.erb +0 -2
  183. data/lib/action_dispatch/testing/performance_test.rb +0 -10
  184. data/lib/action_view/asset_paths.rb +0 -142
  185. data/lib/action_view/base.rb +0 -220
  186. data/lib/action_view/buffers.rb +0 -43
  187. data/lib/action_view/context.rb +0 -36
  188. data/lib/action_view/flows.rb +0 -79
  189. data/lib/action_view/helpers/active_model_helper.rb +0 -50
  190. data/lib/action_view/helpers/asset_paths.rb +0 -7
  191. data/lib/action_view/helpers/asset_tag_helper.rb +0 -457
  192. data/lib/action_view/helpers/asset_tag_helpers/asset_include_tag.rb +0 -146
  193. data/lib/action_view/helpers/asset_tag_helpers/asset_paths.rb +0 -93
  194. data/lib/action_view/helpers/asset_tag_helpers/javascript_tag_helpers.rb +0 -193
  195. data/lib/action_view/helpers/asset_tag_helpers/stylesheet_tag_helpers.rb +0 -148
  196. data/lib/action_view/helpers/atom_feed_helper.rb +0 -200
  197. data/lib/action_view/helpers/cache_helper.rb +0 -64
  198. data/lib/action_view/helpers/capture_helper.rb +0 -203
  199. data/lib/action_view/helpers/controller_helper.rb +0 -25
  200. data/lib/action_view/helpers/csrf_helper.rb +0 -32
  201. data/lib/action_view/helpers/date_helper.rb +0 -1062
  202. data/lib/action_view/helpers/debug_helper.rb +0 -40
  203. data/lib/action_view/helpers/form_helper.rb +0 -1486
  204. data/lib/action_view/helpers/form_options_helper.rb +0 -658
  205. data/lib/action_view/helpers/form_tag_helper.rb +0 -685
  206. data/lib/action_view/helpers/javascript_helper.rb +0 -110
  207. data/lib/action_view/helpers/number_helper.rb +0 -622
  208. data/lib/action_view/helpers/output_safety_helper.rb +0 -38
  209. data/lib/action_view/helpers/record_tag_helper.rb +0 -111
  210. data/lib/action_view/helpers/rendering_helper.rb +0 -90
  211. data/lib/action_view/helpers/sanitize_helper.rb +0 -259
  212. data/lib/action_view/helpers/tag_helper.rb +0 -160
  213. data/lib/action_view/helpers/text_helper.rb +0 -426
  214. data/lib/action_view/helpers/translation_helper.rb +0 -91
  215. data/lib/action_view/helpers/url_helper.rb +0 -693
  216. data/lib/action_view/helpers.rb +0 -60
  217. data/lib/action_view/locale/en.yml +0 -160
  218. data/lib/action_view/log_subscriber.rb +0 -28
  219. data/lib/action_view/lookup_context.rb +0 -254
  220. data/lib/action_view/path_set.rb +0 -89
  221. data/lib/action_view/railtie.rb +0 -55
  222. data/lib/action_view/renderer/abstract_renderer.rb +0 -41
  223. data/lib/action_view/renderer/partial_renderer.rb +0 -415
  224. data/lib/action_view/renderer/renderer.rb +0 -54
  225. data/lib/action_view/renderer/streaming_template_renderer.rb +0 -106
  226. data/lib/action_view/renderer/template_renderer.rb +0 -94
  227. data/lib/action_view/template/error.rb +0 -128
  228. data/lib/action_view/template/handlers/builder.rb +0 -26
  229. data/lib/action_view/template/handlers/erb.rb +0 -125
  230. data/lib/action_view/template/handlers.rb +0 -50
  231. data/lib/action_view/template/resolver.rb +0 -272
  232. data/lib/action_view/template/text.rb +0 -30
  233. data/lib/action_view/template.rb +0 -337
  234. data/lib/action_view/test_case.rb +0 -245
  235. data/lib/action_view/testing/resolvers.rb +0 -50
  236. data/lib/action_view.rb +0 -84
  237. data/lib/sprockets/assets.rake +0 -99
  238. data/lib/sprockets/bootstrap.rb +0 -37
  239. data/lib/sprockets/compressors.rb +0 -83
  240. data/lib/sprockets/helpers/isolated_helper.rb +0 -13
  241. data/lib/sprockets/helpers/rails_helper.rb +0 -182
  242. data/lib/sprockets/helpers.rb +0 -6
  243. data/lib/sprockets/railtie.rb +0 -62
  244. data/lib/sprockets/static_compiler.rb +0 -56
@@ -1,31 +1,38 @@
1
- require 'journey'
1
+ require 'action_dispatch/journey'
2
2
  require 'forwardable'
3
- require 'active_support/core_ext/object/blank'
3
+ require 'active_support/concern'
4
4
  require 'active_support/core_ext/object/to_query'
5
5
  require 'active_support/core_ext/hash/slice'
6
6
  require 'active_support/core_ext/module/remove_method'
7
+ require 'active_support/core_ext/array/extract_options'
8
+ require 'active_support/core_ext/string/filters'
7
9
  require 'action_controller/metal/exceptions'
10
+ require 'action_dispatch/http/request'
11
+ require 'action_dispatch/routing/endpoint'
8
12
 
9
13
  module ActionDispatch
10
14
  module Routing
11
- class RouteSet #:nodoc:
15
+ # :stopdoc:
16
+ class RouteSet
12
17
  # Since the router holds references to many parts of the system
13
18
  # like engines, controllers and the application itself, inspecting
14
19
  # the route set can actually be really slow, therefore we default
15
20
  # alias inspect to to_s.
16
21
  alias inspect to_s
17
22
 
18
- PARAMETERS_KEY = 'action_dispatch.request.path_parameters'
23
+ mattr_accessor :relative_url_root
19
24
 
20
- class Dispatcher #:nodoc:
21
- def initialize(options={})
22
- @defaults = options[:defaults]
23
- @glob_param = options.delete(:glob)
24
- @controllers = {}
25
+ class Dispatcher < Routing::Endpoint
26
+ def initialize(defaults)
27
+ @defaults = defaults
25
28
  end
26
29
 
27
- def call(env)
28
- params = env[PARAMETERS_KEY]
30
+ def dispatcher?; true; end
31
+
32
+ def serve(req)
33
+ req.check_path_parameters!
34
+ params = req.path_parameters
35
+
29
36
  prepare_params!(params)
30
37
 
31
38
  # Just raise undefined constant errors if a controller was specified as default.
@@ -33,13 +40,12 @@ module ActionDispatch
33
40
  return [404, {'X-Cascade' => 'pass'}, []]
34
41
  end
35
42
 
36
- dispatch(controller, params[:action], env)
43
+ dispatch(controller, params[:action], req.env)
37
44
  end
38
45
 
39
46
  def prepare_params!(params)
40
47
  normalize_controller!(params)
41
48
  merge_default_action!(params)
42
- split_glob_param!(params) if @glob_param
43
49
  end
44
50
 
45
51
  # If this is a default_controller (i.e. a controller specified by the user)
@@ -60,13 +66,8 @@ module ActionDispatch
60
66
  private
61
67
 
62
68
  def controller_reference(controller_param)
63
- controller_name = "#{controller_param.camelize}Controller"
64
-
65
- unless controller = @controllers[controller_param]
66
- controller = @controllers[controller_param] =
67
- ActiveSupport::Dependencies.reference(controller_name)
68
- end
69
- controller.get(controller_name)
69
+ const_name = "#{controller_param.camelize}Controller"
70
+ ActiveSupport::Dependencies.constantize(const_name)
70
71
  end
71
72
 
72
73
  def dispatch(controller, action, env)
@@ -80,48 +81,79 @@ module ActionDispatch
80
81
  def merge_default_action!(params)
81
82
  params[:action] ||= 'index'
82
83
  end
83
-
84
- def split_glob_param!(params)
85
- params[@glob_param] = params[@glob_param].split('/').map { |v| URI.parser.unescape(v) }
86
- end
87
84
  end
88
85
 
89
86
  # A NamedRouteCollection instance is a collection of named routes, and also
90
87
  # maintains an anonymous module that can be used to install helpers for the
91
88
  # named routes.
92
- class NamedRouteCollection #:nodoc:
89
+ class NamedRouteCollection
93
90
  include Enumerable
94
- attr_reader :routes, :helpers, :module
91
+ attr_reader :routes, :url_helpers_module
95
92
 
96
93
  def initialize
97
- @routes = {}
98
- @helpers = []
94
+ @routes = {}
95
+ @path_helpers = Set.new
96
+ @url_helpers = Set.new
97
+ @url_helpers_module = Module.new
98
+ @path_helpers_module = Module.new
99
+ end
100
+
101
+ def route_defined?(name)
102
+ key = name.to_sym
103
+ @path_helpers.include?(key) || @url_helpers.include?(key)
104
+ end
99
105
 
100
- @module = Module.new
106
+ def helpers
107
+ ActiveSupport::Deprecation.warn(<<-MSG.squish)
108
+ `named_routes.helpers` is deprecated, please use `route_defined?(route_name)`
109
+ to see if a named route was defined.
110
+ MSG
111
+ @path_helpers + @url_helpers
101
112
  end
102
113
 
103
114
  def helper_names
104
- self.module.instance_methods.map(&:to_s)
115
+ @path_helpers.map(&:to_s) + @url_helpers.map(&:to_s)
105
116
  end
106
117
 
107
118
  def clear!
108
- @helpers.each do |helper|
109
- @module.remove_possible_method helper
119
+ @path_helpers.each do |helper|
120
+ @path_helpers_module.send :undef_method, helper
121
+ end
122
+
123
+ @url_helpers.each do |helper|
124
+ @url_helpers_module.send :undef_method, helper
110
125
  end
111
126
 
112
127
  @routes.clear
113
- @helpers.clear
128
+ @path_helpers.clear
129
+ @url_helpers.clear
114
130
  end
115
131
 
116
132
  def add(name, route)
117
- routes[name.to_sym] = route
118
- define_named_route_methods(name, route)
133
+ key = name.to_sym
134
+ path_name = :"#{name}_path"
135
+ url_name = :"#{name}_url"
136
+
137
+ if routes.key? key
138
+ @path_helpers_module.send :undef_method, path_name
139
+ @url_helpers_module.send :undef_method, url_name
140
+ end
141
+ routes[key] = route
142
+ define_url_helper @path_helpers_module, route, path_name, route.defaults, name, LEGACY
143
+ define_url_helper @url_helpers_module, route, url_name, route.defaults, name, UNKNOWN
144
+
145
+ @path_helpers << path_name
146
+ @url_helpers << url_name
119
147
  end
120
148
 
121
149
  def get(name)
122
150
  routes[name.to_sym]
123
151
  end
124
152
 
153
+ def key?(name)
154
+ routes.key? name.to_sym
155
+ end
156
+
125
157
  alias []= add
126
158
  alias [] get
127
159
  alias clear clear!
@@ -139,90 +171,217 @@ module ActionDispatch
139
171
  routes.length
140
172
  end
141
173
 
142
- def reset!
143
- old_routes = routes.dup
144
- clear!
145
- old_routes.each do |name, route|
146
- add(name, route)
147
- end
148
- end
174
+ def path_helpers_module(warn = false)
175
+ if warn
176
+ mod = @path_helpers_module
177
+ helpers = @path_helpers
178
+ Module.new do
179
+ include mod
149
180
 
150
- def install(destinations = [ActionController::Base, ActionView::Base], regenerate = false)
151
- reset! if regenerate
152
- Array(destinations).each do |dest|
153
- dest.__send__(:include, @module)
181
+ helpers.each do |meth|
182
+ define_method(meth) do |*args, &block|
183
+ ActiveSupport::Deprecation.warn("The method `#{meth}` cannot be used here as a full URL is required. Use `#{meth.to_s.sub(/_path$/, '_url')}` instead")
184
+ super(*args, &block)
185
+ end
186
+ end
187
+ end
188
+ else
189
+ @path_helpers_module
154
190
  end
155
191
  end
156
192
 
157
- private
158
- def url_helper_name(name, kind = :url)
159
- :"#{name}_#{kind}"
193
+ class UrlHelper
194
+ def self.create(route, options, route_name, url_strategy)
195
+ if optimize_helper?(route)
196
+ OptimizedUrlHelper.new(route, options, route_name, url_strategy)
197
+ else
198
+ new route, options, route_name, url_strategy
199
+ end
160
200
  end
161
201
 
162
- def hash_access_name(name, kind = :url)
163
- :"hash_for_#{name}_#{kind}"
202
+ def self.optimize_helper?(route)
203
+ !route.glob? && route.path.requirements.empty?
164
204
  end
165
205
 
166
- def define_named_route_methods(name, route)
167
- {:url => {:only_path => false}, :path => {:only_path => true}}.each do |kind, opts|
168
- hash = route.defaults.merge(:use_route => name).merge(opts)
169
- define_hash_access route, name, kind, hash
170
- define_url_helper route, name, kind, hash
206
+ attr_reader :url_strategy, :route_name
207
+
208
+ class OptimizedUrlHelper < UrlHelper
209
+ attr_reader :arg_size
210
+
211
+ def initialize(route, options, route_name, url_strategy)
212
+ super
213
+ @required_parts = @route.required_parts
214
+ @arg_size = @required_parts.size
215
+ end
216
+
217
+ def call(t, args, inner_options)
218
+ if args.size == arg_size && !inner_options && optimize_routes_generation?(t)
219
+ options = t.url_options.merge @options
220
+ options[:path] = optimized_helper(args)
221
+ url_strategy.call options
222
+ else
223
+ super
224
+ end
225
+ end
226
+
227
+ private
228
+
229
+ def optimized_helper(args)
230
+ params = parameterize_args(args)
231
+ missing_keys = missing_keys(params)
232
+
233
+ unless missing_keys.empty?
234
+ raise_generation_error(params, missing_keys)
235
+ end
236
+
237
+ @route.format params
238
+ end
239
+
240
+ def optimize_routes_generation?(t)
241
+ t.send(:optimize_routes_generation?)
242
+ end
243
+
244
+ def parameterize_args(args)
245
+ params = {}
246
+ @required_parts.zip(args.map(&:to_param)) { |k,v| params[k] = v }
247
+ params
248
+ end
249
+
250
+ def missing_keys(args)
251
+ args.select{ |part, arg| arg.nil? || arg.empty? }.keys
252
+ end
253
+
254
+ def raise_generation_error(args, missing_keys)
255
+ constraints = Hash[@route.requirements.merge(args).sort_by{|k,v| k.to_s}]
256
+ message = "No route matches #{constraints.inspect}"
257
+ message << " missing required keys: #{missing_keys.sort.inspect}"
258
+
259
+ raise ActionController::UrlGenerationError, message
171
260
  end
172
261
  end
173
262
 
174
- def define_hash_access(route, name, kind, options)
175
- selector = hash_access_name(name, kind)
263
+ def initialize(route, options, route_name, url_strategy)
264
+ @options = options
265
+ @segment_keys = route.segment_keys.uniq
266
+ @route = route
267
+ @url_strategy = url_strategy
268
+ @route_name = route_name
269
+ end
176
270
 
177
- # We use module_eval to avoid leaks
178
- @module.module_eval <<-END_EVAL, __FILE__, __LINE__ + 1
179
- remove_possible_method :#{selector}
180
- def #{selector}(*args)
181
- options = args.extract_options!
182
- result = #{options.inspect}
271
+ def call(t, args, inner_options)
272
+ controller_options = t.url_options
273
+ options = controller_options.merge @options
274
+ hash = handle_positional_args(controller_options,
275
+ deprecate_string_options(inner_options) || {},
276
+ args,
277
+ options,
278
+ @segment_keys)
183
279
 
184
- if args.size > 0
185
- result[:_positional_args] = args
186
- result[:_positional_keys] = #{route.segment_keys.inspect}
187
- end
280
+ t._routes.url_for(hash, route_name, url_strategy)
281
+ end
282
+
283
+ def handle_positional_args(controller_options, inner_options, args, result, path_params)
284
+ if args.size > 0
285
+ # take format into account
286
+ if path_params.include?(:format)
287
+ path_params_size = path_params.size - 1
288
+ else
289
+ path_params_size = path_params.size
290
+ end
188
291
 
189
- result.merge(options)
292
+ if args.size < path_params_size
293
+ path_params -= controller_options.keys
294
+ path_params -= result.keys
190
295
  end
191
- protected :#{selector}
192
- END_EVAL
193
- helpers << selector
296
+ path_params.each { |param|
297
+ value = inner_options.fetch(param) { args.shift }
298
+
299
+ unless param == :format && value.nil?
300
+ result[param] = value
301
+ end
302
+ }
303
+ end
304
+
305
+ result.merge!(inner_options)
194
306
  end
195
307
 
196
- # Create a url helper allowing ordered parameters to be associated
197
- # with corresponding dynamic segments, so you can do:
198
- #
199
- # foo_url(bar, baz, bang)
200
- #
201
- # Instead of:
202
- #
203
- # foo_url(:bar => bar, :baz => baz, :bang => bang)
204
- #
205
- # Also allow options hash, so you can do:
206
- #
207
- # foo_url(bar, baz, bang, :sort_by => 'baz')
208
- #
209
- def define_url_helper(route, name, kind, options)
210
- selector = url_helper_name(name, kind)
211
- hash_access_method = hash_access_name(name, kind)
212
-
213
- @module.module_eval <<-END_EVAL, __FILE__, __LINE__ + 1
214
- remove_possible_method :#{selector}
215
- def #{selector}(*args)
216
- url_for(#{hash_access_method}(*args))
308
+ DEPRECATED_STRING_OPTIONS = %w[controller action]
309
+
310
+ def deprecate_string_options(options)
311
+ options ||= {}
312
+ deprecated_string_options = options.keys & DEPRECATED_STRING_OPTIONS
313
+ if deprecated_string_options.any?
314
+ msg = "Calling URL helpers with string keys #{deprecated_string_options.join(", ")} is deprecated. Use symbols instead."
315
+ ActiveSupport::Deprecation.warn(msg)
316
+ deprecated_string_options.each do |option|
317
+ value = options.delete(option)
318
+ options[option.to_sym] = value
217
319
  end
218
- END_EVAL
219
- helpers << selector
320
+ end
321
+ options
220
322
  end
323
+ end
324
+
325
+ private
326
+ # Create a url helper allowing ordered parameters to be associated
327
+ # with corresponding dynamic segments, so you can do:
328
+ #
329
+ # foo_url(bar, baz, bang)
330
+ #
331
+ # Instead of:
332
+ #
333
+ # foo_url(bar: bar, baz: baz, bang: bang)
334
+ #
335
+ # Also allow options hash, so you can do:
336
+ #
337
+ # foo_url(bar, baz, bang, sort_by: 'baz')
338
+ #
339
+ def define_url_helper(mod, route, name, opts, route_key, url_strategy)
340
+ helper = UrlHelper.create(route, opts, route_key, url_strategy)
341
+ mod.module_eval do
342
+ define_method(name) do |*args|
343
+ options = nil
344
+ options = args.pop if args.last.is_a? Hash
345
+ helper.call self, args, options
346
+ end
347
+ end
348
+ end
221
349
  end
222
350
 
351
+ # strategy for building urls to send to the client
352
+ PATH = ->(options) { ActionDispatch::Http::URL.path_for(options) }
353
+ FULL = ->(options) { ActionDispatch::Http::URL.full_url_for(options) }
354
+ UNKNOWN = ->(options) { ActionDispatch::Http::URL.url_for(options) }
355
+ LEGACY = ->(options) {
356
+ if options.key?(:only_path)
357
+ if options[:only_path]
358
+ ActiveSupport::Deprecation.warn(<<-MSG.squish)
359
+ You are calling a `*_path` helper with the `only_path` option
360
+ explicitly set to `true`. This option will stop working on
361
+ path helpers in Rails 5. Simply remove the `only_path: true`
362
+ argument from your call as it is redundant when applied to a
363
+ path helper.
364
+ MSG
365
+
366
+ PATH.call(options)
367
+ else
368
+ ActiveSupport::Deprecation.warn(<<-MSG.squish)
369
+ You are calling a `*_path` helper with the `only_path` option
370
+ explicitly set to `false`. This option will stop working on
371
+ path helpers in Rails 5. Use the corresponding `*_url` helper
372
+ instead.
373
+ MSG
374
+
375
+ FULL.call(options)
376
+ end
377
+ else
378
+ PATH.call(options)
379
+ end
380
+ }
381
+
223
382
  attr_accessor :formatter, :set, :named_routes, :default_scope, :router
224
383
  attr_accessor :disable_clear_and_finalize, :resources_path_names
225
- attr_accessor :default_url_options, :request_class, :valid_conditions
384
+ attr_accessor :default_url_options, :request_class
226
385
 
227
386
  alias :routes :set
228
387
 
@@ -232,19 +391,9 @@ module ActionDispatch
232
391
 
233
392
  def initialize(request_class = ActionDispatch::Request)
234
393
  self.named_routes = NamedRouteCollection.new
235
- self.resources_path_names = self.class.default_resources_path_names.dup
394
+ self.resources_path_names = self.class.default_resources_path_names
236
395
  self.default_url_options = {}
237
-
238
396
  self.request_class = request_class
239
- @valid_conditions = {}
240
-
241
- request_class.public_instance_methods.each { |m|
242
- @valid_conditions[m.to_sym] = true
243
- }
244
- @valid_conditions[:controller] = true
245
- @valid_conditions[:action] = true
246
-
247
- self.valid_conditions.delete(:id)
248
397
 
249
398
  @append = []
250
399
  @prepend = []
@@ -252,9 +401,7 @@ module ActionDispatch
252
401
  @finalized = false
253
402
 
254
403
  @set = Journey::Routes.new
255
- @router = Journey::Router.new(@set, {
256
- :parameters_key => PARAMETERS_KEY,
257
- :request_class => request_class})
404
+ @router = Journey::Router.new @set
258
405
  @formatter = Journey::Formatter.new @set
259
406
  end
260
407
 
@@ -285,6 +432,7 @@ module ActionDispatch
285
432
  mapper.instance_exec(&block)
286
433
  end
287
434
  end
435
+ private :eval_block
288
436
 
289
437
  def finalize!
290
438
  return if @finalized
@@ -300,14 +448,19 @@ module ActionDispatch
300
448
  @prepend.each { |blk| eval_block(blk) }
301
449
  end
302
450
 
303
- def install_helpers(destinations = [ActionController::Base, ActionView::Base], regenerate_code = false)
304
- Array(destinations).each { |d| d.module_eval { include Helpers } }
305
- named_routes.install(destinations, regenerate_code)
451
+ def dispatcher(defaults)
452
+ Routing::RouteSet::Dispatcher.new(defaults)
306
453
  end
307
454
 
308
455
  module MountedHelpers
456
+ extend ActiveSupport::Concern
457
+ include UrlFor
309
458
  end
310
459
 
460
+ # Contains all the mounted helpers across different
461
+ # engines and the `main_app` helper for the application.
462
+ # You can include this in your classes if you want to
463
+ # access routes for other engines.
311
464
  def mounted_helpers
312
465
  MountedHelpers
313
466
  end
@@ -316,45 +469,72 @@ module ActionDispatch
316
469
  return if MountedHelpers.method_defined?(name)
317
470
 
318
471
  routes = self
472
+ helpers = routes.url_helpers
473
+
319
474
  MountedHelpers.class_eval do
320
475
  define_method "_#{name}" do
321
- RoutesProxy.new(routes, self._routes_context)
476
+ RoutesProxy.new(routes, _routes_context, helpers)
322
477
  end
323
478
  end
324
479
 
325
- MountedHelpers.class_eval <<-RUBY
480
+ MountedHelpers.class_eval(<<-RUBY, __FILE__, __LINE__ + 1)
326
481
  def #{name}
327
- @#{name} ||= _#{name}
482
+ @_#{name} ||= _#{name}
328
483
  end
329
484
  RUBY
330
485
  end
331
486
 
332
- def url_helpers
333
- @url_helpers ||= begin
334
- routes = self
487
+ def url_helpers(supports_path = true)
488
+ routes = self
335
489
 
336
- helpers = Module.new do
337
- extend ActiveSupport::Concern
338
- include UrlFor
490
+ Module.new do
491
+ extend ActiveSupport::Concern
492
+ include UrlFor
493
+
494
+ # Define url_for in the singleton level so one can do:
495
+ # Rails.application.routes.url_helpers.url_for(args)
496
+ @_routes = routes
497
+ class << self
498
+ delegate :url_for, :optimize_routes_generation?, to: '@_routes'
499
+ attr_reader :_routes
500
+ def url_options; {}; end
501
+ end
339
502
 
340
- @_routes = routes
341
- class << self
342
- delegate :url_for, :to => '@_routes'
343
- end
344
- extend routes.named_routes.module
345
-
346
- # ROUTES TODO: install_helpers isn't great... can we make a module with the stuff that
347
- # we can include?
348
- # Yes plz - JP
349
- included do
350
- routes.install_helpers(self)
351
- singleton_class.send(:redefine_method, :_routes) { routes }
352
- end
503
+ url_helpers = routes.named_routes.url_helpers_module
504
+
505
+ # Make named_routes available in the module singleton
506
+ # as well, so one can do:
507
+ # Rails.application.routes.url_helpers.posts_path
508
+ extend url_helpers
509
+
510
+ # Any class that includes this module will get all
511
+ # named routes...
512
+ include url_helpers
353
513
 
354
- define_method(:_routes) { @_routes || routes }
514
+ if supports_path
515
+ path_helpers = routes.named_routes.path_helpers_module
516
+ else
517
+ path_helpers = routes.named_routes.path_helpers_module(true)
355
518
  end
356
519
 
357
- helpers
520
+ include path_helpers
521
+ extend path_helpers
522
+
523
+ # plus a singleton class method called _routes ...
524
+ included do
525
+ singleton_class.send(:redefine_method, :_routes) { routes }
526
+ end
527
+
528
+ # And an instance method _routes. Note that
529
+ # UrlFor (included in this module) add extra
530
+ # conveniences for working with @_routes.
531
+ define_method(:_routes) { @_routes || routes }
532
+
533
+ define_method(:_generate_paths_by_default) do
534
+ supports_path
535
+ end
536
+
537
+ private :_generate_paths_by_default
358
538
  end
359
539
  end
360
540
 
@@ -365,16 +545,27 @@ module ActionDispatch
365
545
  def add_route(app, conditions = {}, requirements = {}, defaults = {}, name = nil, anchor = true)
366
546
  raise ArgumentError, "Invalid route name: '#{name}'" unless name.blank? || name.to_s.match(/^[_a-z]\w*$/i)
367
547
 
368
- path = build_path(conditions.delete(:path_info), requirements, SEPARATORS, anchor)
369
- conditions = build_conditions(conditions, valid_conditions, path.names.map { |x| x.to_sym })
548
+ if name && named_routes[name]
549
+ raise ArgumentError, "Invalid route name, already in use: '#{name}' \n" \
550
+ "You may have defined two routes with the same name using the `:as` option, or " \
551
+ "you may be overriding a route already defined by a resource with the same naming. " \
552
+ "For the latter, you can restrict the routes created with `resources` as explained here: \n" \
553
+ "http://guides.rubyonrails.org/routing.html#restricting-the-routes-created"
554
+ end
555
+
556
+ path = conditions.delete :path_info
557
+ ast = conditions.delete :parsed_path_info
558
+ path = build_path(path, ast, requirements, anchor)
559
+ conditions = build_conditions(conditions, path.names.map { |x| x.to_sym })
370
560
 
371
561
  route = @set.add_route(app, path, conditions, defaults, name)
372
562
  named_routes[name] = route if name
373
563
  route
374
564
  end
375
565
 
376
- def build_path(path, requirements, separators, anchor)
566
+ def build_path(path, ast, requirements, anchor)
377
567
  strexp = Journey::Router::Strexp.new(
568
+ ast,
378
569
  path,
379
570
  requirements,
380
571
  SEPARATORS,
@@ -403,25 +594,26 @@ module ActionDispatch
403
594
  end
404
595
  private :build_path
405
596
 
406
- def build_conditions(current_conditions, req_predicates, path_values)
597
+ def build_conditions(current_conditions, path_values)
407
598
  conditions = current_conditions.dup
408
599
 
409
- verbs = conditions[:request_method] || []
410
-
411
600
  # Rack-Mount requires that :request_method be a regular expression.
412
601
  # :request_method represents the HTTP verb that matches this route.
413
602
  #
414
603
  # Here we munge values before they get sent on to rack-mount.
604
+ verbs = conditions[:request_method] || []
415
605
  unless verbs.empty?
416
606
  conditions[:request_method] = %r[^#{verbs.join('|')}$]
417
607
  end
418
- conditions.delete_if { |k,v| !(req_predicates.include?(k) || path_values.include?(k)) }
419
608
 
420
- conditions
609
+ conditions.keep_if do |k, _|
610
+ k == :action || k == :controller || k == :required_defaults ||
611
+ @request_class.public_method_defined?(k) || path_values.include?(k)
612
+ end
421
613
  end
422
614
  private :build_conditions
423
615
 
424
- class Generator #:nodoc:
616
+ class Generator
425
617
  PARAMETERIZE = lambda do |name, value|
426
618
  if name == :controller
427
619
  value
@@ -434,18 +626,18 @@ module ActionDispatch
434
626
 
435
627
  attr_reader :options, :recall, :set, :named_route
436
628
 
437
- def initialize(options, recall, set, extras = false)
438
- @named_route = options.delete(:use_route)
629
+ def initialize(named_route, options, recall, set)
630
+ @named_route = named_route
439
631
  @options = options.dup
440
632
  @recall = recall.dup
441
633
  @set = set
442
- @extras = extras
443
634
 
635
+ normalize_recall!
444
636
  normalize_options!
445
637
  normalize_controller_action_id!
446
638
  use_relative_controller!
447
639
  normalize_controller!
448
- handle_nil_action!
640
+ normalize_action!
449
641
  end
450
642
 
451
643
  def controller
@@ -458,19 +650,22 @@ module ActionDispatch
458
650
 
459
651
  def use_recall_for(key)
460
652
  if @recall[key] && (!@options.key?(key) || @options[key] == @recall[key])
461
- if named_route_exists?
462
- @options[key] = @recall.delete(key) if segment_keys.include?(key)
463
- else
653
+ if !named_route_exists? || segment_keys.include?(key)
464
654
  @options[key] = @recall.delete(key)
465
655
  end
466
656
  end
467
657
  end
468
658
 
659
+ # Set 'index' as default action for recall
660
+ def normalize_recall!
661
+ @recall[:action] ||= 'index'
662
+ end
663
+
469
664
  def normalize_options!
470
665
  # If an explicit :controller was given, always make :action explicit
471
666
  # too, so that action expiry works as expected for things like
472
667
  #
473
- # generate({:controller => 'content'}, {:controller => 'content', :action => 'show'})
668
+ # generate({controller: 'content'}, {controller: 'content', action: 'show'})
474
669
  #
475
670
  # (the above is from the unit tests). In the above case, because the
476
671
  # controller was explicitly given, but no action, the action is implied to
@@ -481,8 +676,8 @@ module ActionDispatch
481
676
  options[:controller] = options[:controller].to_s
482
677
  end
483
678
 
484
- if options[:action]
485
- options[:action] = options[:action].to_s
679
+ if options.key?(:action)
680
+ options[:action] = (options[:action] || 'index').to_s
486
681
  end
487
682
  end
488
683
 
@@ -492,14 +687,12 @@ module ActionDispatch
492
687
  # :controller, :action or :id is not found, don't pull any
493
688
  # more keys from the recall.
494
689
  def normalize_controller_action_id!
495
- @recall[:action] ||= 'index' if current_controller
496
-
497
690
  use_recall_for(:controller) or return
498
691
  use_recall_for(:action) or return
499
692
  use_recall_for(:id)
500
693
  end
501
694
 
502
- # if the current controller is "foo/bar/baz" and :controller => "baz/bat"
695
+ # if the current controller is "foo/bar/baz" and controller: "baz/bat"
503
696
  # is specified, the controller becomes "foo/baz/bat"
504
697
  def use_relative_controller!
505
698
  if !named_route && different_controller? && !controller.start_with?("/")
@@ -515,29 +708,17 @@ module ActionDispatch
515
708
  @options[:controller] = controller.sub(%r{^/}, '') if controller
516
709
  end
517
710
 
518
- # This handles the case of :action => nil being explicitly passed.
519
- # It is identical to :action => "index"
520
- def handle_nil_action!
521
- if options.has_key?(:action) && options[:action].nil?
522
- options[:action] = 'index'
711
+ # Move 'index' action from options to recall
712
+ def normalize_action!
713
+ if @options[:action] == 'index'
714
+ @recall[:action] = @options.delete(:action)
523
715
  end
524
- recall[:action] = options.delete(:action) if options[:action] == 'index'
525
716
  end
526
717
 
718
+ # Generates a path from routes, returns [path, params].
719
+ # If no route is generated the formatter will raise ActionController::UrlGenerationError
527
720
  def generate
528
- path, params = @set.formatter.generate(:path_info, named_route, options, recall, PARAMETERIZE)
529
-
530
- raise_routing_error unless path
531
-
532
- return [path, params.keys] if @extras
533
-
534
- [path, params]
535
- rescue Journey::Router::RoutingError
536
- raise_routing_error
537
- end
538
-
539
- def raise_routing_error
540
- raise ActionController::RoutingError, "No route matches #{options.inspect}"
721
+ @set.formatter.generate(named_route, options, recall, PARAMETERIZE)
541
722
  end
542
723
 
543
724
  def different_controller?
@@ -562,50 +743,78 @@ module ActionDispatch
562
743
  end
563
744
 
564
745
  def generate_extras(options, recall={})
565
- generate(options, recall, true)
746
+ route_key = options.delete :use_route
747
+ path, params = generate(route_key, options, recall)
748
+ return path, params.keys
566
749
  end
567
750
 
568
- def generate(options, recall = {}, extras = false)
569
- Generator.new(options, recall, self, extras).generate
751
+ def generate(route_key, options, recall = {})
752
+ Generator.new(route_key, options, recall, self).generate
570
753
  end
754
+ private :generate
571
755
 
572
756
  RESERVED_OPTIONS = [:host, :protocol, :port, :subdomain, :domain, :tld_length,
573
- :trailing_slash, :anchor, :params, :only_path, :script_name]
757
+ :trailing_slash, :anchor, :params, :only_path, :script_name,
758
+ :original_script_name, :relative_url_root]
574
759
 
575
- def _generate_prefix(options = {})
576
- nil
760
+ def optimize_routes_generation?
761
+ default_url_options.empty?
762
+ end
763
+
764
+ def find_script_name(options)
765
+ options.delete(:script_name) || find_relative_url_root(options) || ''
766
+ end
767
+
768
+ def find_relative_url_root(options)
769
+ options.delete(:relative_url_root) || relative_url_root
577
770
  end
578
771
 
579
- def url_for(options)
580
- finalize!
581
- options = (options || {}).reverse_merge!(default_url_options)
772
+ def path_for(options, route_name = nil)
773
+ url_for(options, route_name, PATH)
774
+ end
582
775
 
583
- handle_positional_args(options)
776
+ # The +options+ argument must be a hash whose keys are *symbols*.
777
+ def url_for(options, route_name = nil, url_strategy = UNKNOWN)
778
+ options = default_url_options.merge options
584
779
 
585
- user, password = extract_authentication(options)
586
- path_segments = options.delete(:_path_segments)
587
- script_name = options.delete(:script_name)
780
+ user = password = nil
588
781
 
589
- path = (script_name.blank? ? _generate_prefix(options) : script_name.chomp('/')).to_s
782
+ if options[:user] && options[:password]
783
+ user = options.delete :user
784
+ password = options.delete :password
785
+ end
590
786
 
591
- path_options = options.except(*RESERVED_OPTIONS)
592
- path_options = yield(path_options) if block_given?
787
+ recall = options.delete(:_recall) { {} }
593
788
 
594
- path_addition, params = generate(path_options, path_segments || {})
595
- path << path_addition
596
- params.merge!(options[:params] || {})
789
+ original_script_name = options.delete(:original_script_name)
790
+ script_name = find_script_name options
791
+
792
+ if original_script_name
793
+ script_name = original_script_name + script_name
794
+ end
795
+
796
+ path_options = options.dup
797
+ RESERVED_OPTIONS.each { |ro| path_options.delete ro }
798
+
799
+ path, params = generate(route_name, path_options, recall)
800
+
801
+ if options.key? :params
802
+ params.merge! options[:params]
803
+ end
597
804
 
598
- ActionDispatch::Http::URL.url_for(options.merge!({
599
- :path => path,
600
- :params => params,
601
- :user => user,
602
- :password => password
603
- }))
805
+ options[:path] = path
806
+ options[:script_name] = script_name
807
+ options[:params] = params
808
+ options[:user] = user
809
+ options[:password] = password
810
+
811
+ url_strategy.call options
604
812
  end
605
813
 
606
814
  def call(env)
607
- finalize!
608
- @router.call(env)
815
+ req = request_class.new(env)
816
+ req.path_info = Journey::Router::Utils.normalize_path(req.path_info)
817
+ @router.serve(req)
609
818
  end
610
819
 
611
820
  def recognize_path(path, environment = {})
@@ -614,54 +823,38 @@ module ActionDispatch
614
823
  extras = environment[:extras] || {}
615
824
 
616
825
  begin
617
- env = Rack::MockRequest.env_for(path, {:method => method, :params => extras})
826
+ env = Rack::MockRequest.env_for(path, {:method => method})
618
827
  rescue URI::InvalidURIError => e
619
828
  raise ActionController::RoutingError, e.message
620
829
  end
621
830
 
622
- req = @request_class.new(env)
623
- @router.recognize(req) do |route, matches, params|
831
+ req = request_class.new(env)
832
+ @router.recognize(req) do |route, params|
833
+ params.merge!(extras)
624
834
  params.each do |key, value|
625
835
  if value.is_a?(String)
626
- value = value.dup.force_encoding(Encoding::BINARY) if value.encoding_aware?
836
+ value = value.dup.force_encoding(Encoding::BINARY)
627
837
  params[key] = URI.parser.unescape(value)
628
838
  end
629
839
  end
630
-
631
- dispatcher = route.app
632
- while dispatcher.is_a?(Mapper::Constraints) && dispatcher.matches?(env) do
633
- dispatcher = dispatcher.app
634
- end
635
-
636
- if dispatcher.is_a?(Dispatcher) && dispatcher.controller(params, false)
637
- dispatcher.prepare_params!(params)
638
- return params
840
+ old_params = req.path_parameters
841
+ req.path_parameters = old_params.merge params
842
+ app = route.app
843
+ if app.matches?(req) && app.dispatcher?
844
+ dispatcher = app.app
845
+
846
+ if dispatcher.controller(params, false)
847
+ dispatcher.prepare_params!(params)
848
+ return params
849
+ else
850
+ raise ActionController::RoutingError, "A route matches #{path.inspect}, but references missing controller: #{params[:controller].camelize}Controller"
851
+ end
639
852
  end
640
853
  end
641
854
 
642
855
  raise ActionController::RoutingError, "No route matches #{path.inspect}"
643
856
  end
644
-
645
- private
646
-
647
- def extract_authentication(options)
648
- if options[:user] && options[:password]
649
- [options.delete(:user), options.delete(:password)]
650
- else
651
- nil
652
- end
653
- end
654
-
655
- def handle_positional_args(options)
656
- return unless args = options.delete(:_positional_args)
657
-
658
- keys = options.delete(:_positional_keys)
659
- keys -= options.keys if args.size < keys.size - 1 # take format into account
660
-
661
- # Tell url_for to skip default_url_options
662
- options.merge!(Hash[args.zip(keys).map { |v, k| [k, v] }])
663
- end
664
-
665
857
  end
858
+ # :startdoc:
666
859
  end
667
860
  end