actionpack 4.2.11.1 → 6.1.3.2
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of actionpack might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/CHANGELOG.md +291 -489
- data/MIT-LICENSE +1 -1
- data/README.rdoc +9 -9
- data/lib/abstract_controller/asset_paths.rb +2 -0
- data/lib/abstract_controller/base.rb +81 -51
- data/lib/{action_controller → abstract_controller}/caching/fragments.rb +64 -17
- data/lib/abstract_controller/caching.rb +66 -0
- data/lib/abstract_controller/callbacks.rb +61 -33
- data/lib/abstract_controller/collector.rb +9 -13
- data/lib/abstract_controller/error.rb +6 -0
- data/lib/abstract_controller/helpers.rb +115 -99
- data/lib/abstract_controller/logger.rb +2 -0
- data/lib/abstract_controller/railties/routes_helpers.rb +21 -3
- data/lib/abstract_controller/rendering.rb +48 -47
- data/lib/abstract_controller/translation.rb +17 -8
- data/lib/abstract_controller/url_for.rb +2 -0
- data/lib/abstract_controller.rb +13 -5
- data/lib/action_controller/api/api_rendering.rb +16 -0
- data/lib/action_controller/api.rb +150 -0
- data/lib/action_controller/base.rb +29 -24
- data/lib/action_controller/caching.rb +12 -57
- data/lib/action_controller/form_builder.rb +50 -0
- data/lib/action_controller/log_subscriber.rb +17 -19
- data/lib/action_controller/metal/basic_implicit_render.rb +13 -0
- data/lib/action_controller/metal/conditional_get.rb +134 -46
- data/lib/action_controller/metal/content_security_policy.rb +51 -0
- data/lib/action_controller/metal/cookies.rb +6 -4
- data/lib/action_controller/metal/data_streaming.rb +30 -50
- data/lib/action_controller/metal/default_headers.rb +17 -0
- data/lib/action_controller/metal/etag_with_flash.rb +18 -0
- data/lib/action_controller/metal/etag_with_template_digest.rb +21 -16
- data/lib/action_controller/metal/exceptions.rb +63 -15
- data/lib/action_controller/metal/flash.rb +9 -8
- data/lib/action_controller/metal/head.rb +26 -21
- data/lib/action_controller/metal/helpers.rb +37 -18
- data/lib/action_controller/metal/http_authentication.rb +81 -73
- data/lib/action_controller/metal/implicit_render.rb +53 -9
- data/lib/action_controller/metal/instrumentation.rb +32 -35
- data/lib/action_controller/metal/live.rb +102 -120
- data/lib/action_controller/metal/logging.rb +20 -0
- data/lib/action_controller/metal/mime_responds.rb +49 -47
- data/lib/action_controller/metal/parameter_encoding.rb +82 -0
- data/lib/action_controller/metal/params_wrapper.rb +83 -66
- data/lib/action_controller/metal/permissions_policy.rb +46 -0
- data/lib/action_controller/metal/redirecting.rb +53 -32
- data/lib/action_controller/metal/renderers.rb +87 -44
- data/lib/action_controller/metal/rendering.rb +77 -50
- data/lib/action_controller/metal/request_forgery_protection.rb +267 -103
- data/lib/action_controller/metal/rescue.rb +10 -17
- data/lib/action_controller/metal/streaming.rb +12 -11
- data/lib/action_controller/metal/strong_parameters.rb +714 -186
- data/lib/action_controller/metal/testing.rb +2 -17
- data/lib/action_controller/metal/url_for.rb +19 -10
- data/lib/action_controller/metal.rb +104 -87
- data/lib/action_controller/railtie.rb +28 -10
- data/lib/action_controller/railties/helpers.rb +3 -1
- data/lib/action_controller/renderer.rb +141 -0
- data/lib/action_controller/template_assertions.rb +11 -0
- data/lib/action_controller/test_case.rb +296 -422
- data/lib/action_controller.rb +34 -23
- data/lib/action_dispatch/http/cache.rb +107 -56
- data/lib/action_dispatch/http/content_disposition.rb +45 -0
- data/lib/action_dispatch/http/content_security_policy.rb +286 -0
- data/lib/action_dispatch/http/filter_parameters.rb +32 -25
- data/lib/action_dispatch/http/filter_redirect.rb +10 -12
- data/lib/action_dispatch/http/headers.rb +55 -22
- data/lib/action_dispatch/http/mime_negotiation.rb +79 -51
- data/lib/action_dispatch/http/mime_type.rb +153 -121
- data/lib/action_dispatch/http/mime_types.rb +20 -6
- data/lib/action_dispatch/http/parameters.rb +90 -40
- data/lib/action_dispatch/http/permissions_policy.rb +173 -0
- data/lib/action_dispatch/http/rack_cache.rb +2 -0
- data/lib/action_dispatch/http/request.rb +226 -121
- data/lib/action_dispatch/http/response.rb +248 -113
- data/lib/action_dispatch/http/upload.rb +21 -7
- data/lib/action_dispatch/http/url.rb +182 -100
- data/lib/action_dispatch/journey/formatter.rb +90 -43
- data/lib/action_dispatch/journey/gtg/builder.rb +28 -41
- data/lib/action_dispatch/journey/gtg/simulator.rb +11 -16
- data/lib/action_dispatch/journey/gtg/transition_table.rb +23 -21
- data/lib/action_dispatch/journey/nfa/dot.rb +3 -14
- data/lib/action_dispatch/journey/nodes/node.rb +29 -15
- data/lib/action_dispatch/journey/parser.rb +17 -16
- data/lib/action_dispatch/journey/parser.y +4 -3
- data/lib/action_dispatch/journey/parser_extras.rb +12 -4
- data/lib/action_dispatch/journey/path/pattern.rb +58 -54
- data/lib/action_dispatch/journey/route.rb +100 -32
- data/lib/action_dispatch/journey/router/utils.rb +29 -18
- data/lib/action_dispatch/journey/router.rb +55 -51
- data/lib/action_dispatch/journey/routes.rb +17 -17
- data/lib/action_dispatch/journey/scanner.rb +26 -17
- data/lib/action_dispatch/journey/visitors.rb +98 -54
- data/lib/action_dispatch/journey.rb +5 -5
- data/lib/action_dispatch/middleware/actionable_exceptions.rb +46 -0
- data/lib/action_dispatch/middleware/callbacks.rb +3 -6
- data/lib/action_dispatch/middleware/cookies.rb +347 -217
- data/lib/action_dispatch/middleware/debug_exceptions.rb +135 -63
- data/lib/action_dispatch/middleware/debug_locks.rb +124 -0
- data/lib/action_dispatch/middleware/debug_view.rb +66 -0
- data/lib/action_dispatch/middleware/exception_wrapper.rb +115 -71
- data/lib/action_dispatch/middleware/executor.rb +21 -0
- data/lib/action_dispatch/middleware/flash.rb +78 -54
- data/lib/action_dispatch/middleware/host_authorization.rb +130 -0
- data/lib/action_dispatch/middleware/public_exceptions.rb +32 -27
- data/lib/action_dispatch/middleware/reloader.rb +5 -91
- data/lib/action_dispatch/middleware/remote_ip.rb +53 -45
- data/lib/action_dispatch/middleware/request_id.rb +17 -10
- data/lib/action_dispatch/middleware/session/abstract_store.rb +41 -26
- data/lib/action_dispatch/middleware/session/cache_store.rb +24 -14
- data/lib/action_dispatch/middleware/session/cookie_store.rb +74 -75
- data/lib/action_dispatch/middleware/session/mem_cache_store.rb +8 -2
- data/lib/action_dispatch/middleware/show_exceptions.rb +28 -23
- data/lib/action_dispatch/middleware/ssl.rb +118 -35
- data/lib/action_dispatch/middleware/stack.rb +82 -41
- data/lib/action_dispatch/middleware/static.rb +156 -89
- data/lib/action_dispatch/middleware/templates/rescues/_actions.html.erb +13 -0
- data/lib/action_dispatch/middleware/templates/rescues/_actions.text.erb +0 -0
- data/lib/action_dispatch/middleware/templates/rescues/_message_and_suggestions.html.erb +22 -0
- data/lib/action_dispatch/middleware/templates/rescues/_request_and_response.html.erb +4 -14
- data/lib/action_dispatch/middleware/templates/rescues/_request_and_response.text.erb +1 -1
- data/lib/action_dispatch/middleware/templates/rescues/{_source.erb → _source.html.erb} +4 -2
- data/lib/action_dispatch/middleware/templates/rescues/_source.text.erb +8 -0
- data/lib/action_dispatch/middleware/templates/rescues/_trace.html.erb +45 -35
- data/lib/action_dispatch/middleware/templates/rescues/blocked_host.html.erb +7 -0
- data/lib/action_dispatch/middleware/templates/rescues/blocked_host.text.erb +5 -0
- data/lib/action_dispatch/middleware/templates/rescues/diagnostics.html.erb +23 -4
- data/lib/action_dispatch/middleware/templates/rescues/diagnostics.text.erb +1 -1
- data/lib/action_dispatch/middleware/templates/rescues/invalid_statement.html.erb +24 -0
- data/lib/action_dispatch/middleware/templates/rescues/invalid_statement.text.erb +15 -0
- data/lib/action_dispatch/middleware/templates/rescues/layout.erb +105 -8
- data/lib/action_dispatch/middleware/templates/rescues/missing_exact_template.html.erb +19 -0
- data/lib/action_dispatch/middleware/templates/rescues/missing_exact_template.text.erb +3 -0
- data/lib/action_dispatch/middleware/templates/rescues/missing_template.html.erb +2 -2
- data/lib/action_dispatch/middleware/templates/rescues/routing_error.html.erb +1 -1
- data/lib/action_dispatch/middleware/templates/rescues/template_error.html.erb +3 -3
- data/lib/action_dispatch/middleware/templates/rescues/template_error.text.erb +1 -1
- data/lib/action_dispatch/middleware/templates/rescues/unknown_action.html.erb +1 -1
- data/lib/action_dispatch/middleware/templates/routes/_route.html.erb +4 -4
- data/lib/action_dispatch/middleware/templates/routes/_table.html.erb +87 -64
- data/lib/action_dispatch/railtie.rb +27 -13
- data/lib/action_dispatch/request/session.rb +109 -61
- data/lib/action_dispatch/request/utils.rb +90 -23
- data/lib/action_dispatch/routing/endpoint.rb +9 -2
- data/lib/action_dispatch/routing/inspector.rb +141 -102
- data/lib/action_dispatch/routing/mapper.rb +811 -473
- data/lib/action_dispatch/routing/polymorphic_routes.rb +167 -143
- data/lib/action_dispatch/routing/redirection.rb +37 -27
- data/lib/action_dispatch/routing/route_set.rb +363 -331
- data/lib/action_dispatch/routing/routes_proxy.rb +32 -5
- data/lib/action_dispatch/routing/url_for.rb +66 -26
- data/lib/action_dispatch/routing.rb +36 -36
- data/lib/action_dispatch/system_test_case.rb +190 -0
- data/lib/action_dispatch/system_testing/browser.rb +86 -0
- data/lib/action_dispatch/system_testing/driver.rb +67 -0
- data/lib/action_dispatch/system_testing/server.rb +31 -0
- data/lib/action_dispatch/system_testing/test_helpers/screenshot_helper.rb +138 -0
- data/lib/action_dispatch/system_testing/test_helpers/setup_and_teardown.rb +29 -0
- data/lib/action_dispatch/testing/assertion_response.rb +46 -0
- data/lib/action_dispatch/testing/assertions/response.rb +44 -22
- data/lib/action_dispatch/testing/assertions/routing.rb +47 -31
- data/lib/action_dispatch/testing/assertions.rb +6 -4
- data/lib/action_dispatch/testing/integration.rb +391 -220
- data/lib/action_dispatch/testing/request_encoder.rb +55 -0
- data/lib/action_dispatch/testing/test_process.rb +53 -22
- data/lib/action_dispatch/testing/test_request.rb +27 -34
- data/lib/action_dispatch/testing/test_response.rb +11 -11
- data/lib/action_dispatch.rb +35 -21
- data/lib/action_pack/gem_version.rb +6 -4
- data/lib/action_pack/version.rb +3 -1
- data/lib/action_pack.rb +4 -2
- metadata +78 -48
- data/lib/action_controller/metal/force_ssl.rb +0 -97
- data/lib/action_controller/metal/hide_actions.rb +0 -40
- data/lib/action_controller/metal/rack_delegation.rb +0 -32
- data/lib/action_controller/middleware.rb +0 -39
- data/lib/action_controller/model_naming.rb +0 -12
- data/lib/action_dispatch/http/parameter_filter.rb +0 -72
- data/lib/action_dispatch/journey/backwards.rb +0 -5
- data/lib/action_dispatch/journey/nfa/builder.rb +0 -76
- data/lib/action_dispatch/journey/nfa/simulator.rb +0 -47
- data/lib/action_dispatch/journey/nfa/transition_table.rb +0 -163
- data/lib/action_dispatch/journey/router/strexp.rb +0 -27
- data/lib/action_dispatch/middleware/params_parser.rb +0 -60
- data/lib/action_dispatch/testing/assertions/dom.rb +0 -3
- data/lib/action_dispatch/testing/assertions/selector.rb +0 -3
- data/lib/action_dispatch/testing/assertions/tag.rb +0 -3
@@ -1,14 +1,13 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
require
|
4
|
-
require
|
5
|
-
require
|
6
|
-
require
|
7
|
-
require
|
8
|
-
require
|
9
|
-
require
|
10
|
-
require
|
11
|
-
require 'action_dispatch/routing/endpoint'
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "action_dispatch/journey"
|
4
|
+
require "active_support/core_ext/object/to_query"
|
5
|
+
require "active_support/core_ext/module/redefine_method"
|
6
|
+
require "active_support/core_ext/module/remove_method"
|
7
|
+
require "active_support/core_ext/array/extract_options"
|
8
|
+
require "action_controller/metal/exceptions"
|
9
|
+
require "action_dispatch/http/request"
|
10
|
+
require "action_dispatch/routing/endpoint"
|
12
11
|
|
13
12
|
module ActionDispatch
|
14
13
|
module Routing
|
@@ -20,67 +19,46 @@ module ActionDispatch
|
|
20
19
|
# alias inspect to to_s.
|
21
20
|
alias inspect to_s
|
22
21
|
|
23
|
-
mattr_accessor :relative_url_root
|
24
|
-
|
25
22
|
class Dispatcher < Routing::Endpoint
|
26
|
-
def initialize(
|
27
|
-
@
|
23
|
+
def initialize(raise_on_name_error)
|
24
|
+
@raise_on_name_error = raise_on_name_error
|
28
25
|
end
|
29
26
|
|
30
27
|
def dispatcher?; true; end
|
31
28
|
|
32
29
|
def serve(req)
|
33
|
-
req.
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
dispatch(controller, params[:action], req.env)
|
44
|
-
end
|
45
|
-
|
46
|
-
def prepare_params!(params)
|
47
|
-
normalize_controller!(params)
|
48
|
-
merge_default_action!(params)
|
49
|
-
end
|
50
|
-
|
51
|
-
# If this is a default_controller (i.e. a controller specified by the user)
|
52
|
-
# we should raise an error in case it's not found, because it usually means
|
53
|
-
# a user error. However, if the controller was retrieved through a dynamic
|
54
|
-
# segment, as in :controller(/:action), we should simply return nil and
|
55
|
-
# delegate the control back to Rack cascade. Besides, if this is not a default
|
56
|
-
# controller, it means we should respect the @scope[:module] parameter.
|
57
|
-
def controller(params, default_controller=true)
|
58
|
-
if params && params.key?(:controller)
|
59
|
-
controller_param = params[:controller]
|
60
|
-
controller_reference(controller_param)
|
30
|
+
params = req.path_parameters
|
31
|
+
controller = controller req
|
32
|
+
res = controller.make_response! req
|
33
|
+
dispatch(controller, params[:action], req, res)
|
34
|
+
rescue ActionController::RoutingError
|
35
|
+
if @raise_on_name_error
|
36
|
+
raise
|
37
|
+
else
|
38
|
+
[404, { "X-Cascade" => "pass" }, []]
|
61
39
|
end
|
62
|
-
rescue NameError => e
|
63
|
-
raise ActionController::RoutingError, e.message, e.backtrace if default_controller
|
64
40
|
end
|
65
41
|
|
66
42
|
private
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
43
|
+
def controller(req)
|
44
|
+
req.controller_class
|
45
|
+
rescue NameError => e
|
46
|
+
raise ActionController::RoutingError, e.message, e.backtrace
|
71
47
|
end
|
72
48
|
|
73
|
-
def dispatch(controller, action,
|
74
|
-
controller.
|
49
|
+
def dispatch(controller, action, req, res)
|
50
|
+
controller.dispatch(action, req, res)
|
75
51
|
end
|
52
|
+
end
|
76
53
|
|
77
|
-
|
78
|
-
|
54
|
+
class StaticDispatcher < Dispatcher
|
55
|
+
def initialize(controller_class)
|
56
|
+
super(false)
|
57
|
+
@controller_class = controller_class
|
79
58
|
end
|
80
59
|
|
81
|
-
|
82
|
-
|
83
|
-
end
|
60
|
+
private
|
61
|
+
def controller(_); @controller_class; end
|
84
62
|
end
|
85
63
|
|
86
64
|
# A NamedRouteCollection instance is a collection of named routes, and also
|
@@ -88,10 +66,11 @@ module ActionDispatch
|
|
88
66
|
# named routes.
|
89
67
|
class NamedRouteCollection
|
90
68
|
include Enumerable
|
91
|
-
attr_reader :routes, :url_helpers_module
|
69
|
+
attr_reader :routes, :url_helpers_module, :path_helpers_module
|
70
|
+
private :routes
|
92
71
|
|
93
72
|
def initialize
|
94
|
-
@routes
|
73
|
+
@routes = {}
|
95
74
|
@path_helpers = Set.new
|
96
75
|
@url_helpers = Set.new
|
97
76
|
@url_helpers_module = Module.new
|
@@ -103,25 +82,17 @@ module ActionDispatch
|
|
103
82
|
@path_helpers.include?(key) || @url_helpers.include?(key)
|
104
83
|
end
|
105
84
|
|
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
|
112
|
-
end
|
113
|
-
|
114
85
|
def helper_names
|
115
86
|
@path_helpers.map(&:to_s) + @url_helpers.map(&:to_s)
|
116
87
|
end
|
117
88
|
|
118
89
|
def clear!
|
119
90
|
@path_helpers.each do |helper|
|
120
|
-
@path_helpers_module.
|
91
|
+
@path_helpers_module.remove_method helper
|
121
92
|
end
|
122
93
|
|
123
94
|
@url_helpers.each do |helper|
|
124
|
-
@url_helpers_module.
|
95
|
+
@url_helpers_module.remove_method helper
|
125
96
|
end
|
126
97
|
|
127
98
|
@routes.clear
|
@@ -135,12 +106,14 @@ module ActionDispatch
|
|
135
106
|
url_name = :"#{name}_url"
|
136
107
|
|
137
108
|
if routes.key? key
|
138
|
-
@path_helpers_module.
|
139
|
-
@url_helpers_module.
|
109
|
+
@path_helpers_module.undef_method path_name
|
110
|
+
@url_helpers_module.undef_method url_name
|
140
111
|
end
|
141
112
|
routes[key] = route
|
142
|
-
|
143
|
-
|
113
|
+
|
114
|
+
helper = UrlHelper.create(route, route.defaults, name)
|
115
|
+
define_url_helper @path_helpers_module, path_name, helper, PATH
|
116
|
+
define_url_helper @url_helpers_module, url_name, helper, UNKNOWN
|
144
117
|
|
145
118
|
@path_helpers << path_name
|
146
119
|
@url_helpers << url_name
|
@@ -151,6 +124,7 @@ module ActionDispatch
|
|
151
124
|
end
|
152
125
|
|
153
126
|
def key?(name)
|
127
|
+
return unless name
|
154
128
|
routes.key? name.to_sym
|
155
129
|
end
|
156
130
|
|
@@ -171,53 +145,69 @@ module ActionDispatch
|
|
171
145
|
routes.length
|
172
146
|
end
|
173
147
|
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
148
|
+
# Given a +name+, defines name_path and name_url helpers.
|
149
|
+
# Used by 'direct', 'resolve', and 'polymorphic' route helpers.
|
150
|
+
def add_url_helper(name, defaults, &block)
|
151
|
+
helper = CustomUrlHelper.new(name, defaults, &block)
|
152
|
+
path_name = :"#{name}_path"
|
153
|
+
url_name = :"#{name}_url"
|
180
154
|
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
super(*args, &block)
|
185
|
-
end
|
186
|
-
end
|
155
|
+
@path_helpers_module.module_eval do
|
156
|
+
redefine_method(path_name) do |*args|
|
157
|
+
helper.call(self, args, true)
|
187
158
|
end
|
188
|
-
else
|
189
|
-
@path_helpers_module
|
190
159
|
end
|
160
|
+
|
161
|
+
@url_helpers_module.module_eval do
|
162
|
+
redefine_method(url_name) do |*args|
|
163
|
+
helper.call(self, args, false)
|
164
|
+
end
|
165
|
+
end
|
166
|
+
|
167
|
+
@path_helpers << path_name
|
168
|
+
@url_helpers << url_name
|
169
|
+
|
170
|
+
self
|
191
171
|
end
|
192
172
|
|
193
173
|
class UrlHelper
|
194
|
-
def self.create(route, options, route_name
|
174
|
+
def self.create(route, options, route_name)
|
195
175
|
if optimize_helper?(route)
|
196
|
-
OptimizedUrlHelper.new(route, options, route_name
|
176
|
+
OptimizedUrlHelper.new(route, options, route_name)
|
197
177
|
else
|
198
|
-
new
|
178
|
+
new(route, options, route_name)
|
199
179
|
end
|
200
180
|
end
|
201
181
|
|
202
182
|
def self.optimize_helper?(route)
|
203
|
-
|
183
|
+
route.path.requirements.empty? && !route.glob?
|
204
184
|
end
|
205
185
|
|
206
|
-
attr_reader :
|
186
|
+
attr_reader :route_name
|
207
187
|
|
208
188
|
class OptimizedUrlHelper < UrlHelper
|
209
189
|
attr_reader :arg_size
|
210
190
|
|
211
|
-
def initialize(route, options, route_name
|
191
|
+
def initialize(route, options, route_name)
|
212
192
|
super
|
213
193
|
@required_parts = @route.required_parts
|
214
194
|
@arg_size = @required_parts.size
|
215
195
|
end
|
216
196
|
|
217
|
-
def call(t, args, inner_options)
|
197
|
+
def call(t, method_name, args, inner_options, url_strategy)
|
218
198
|
if args.size == arg_size && !inner_options && optimize_routes_generation?(t)
|
219
199
|
options = t.url_options.merge @options
|
220
200
|
options[:path] = optimized_helper(args)
|
201
|
+
|
202
|
+
original_script_name = options.delete(:original_script_name)
|
203
|
+
script_name = t._routes.find_script_name(options)
|
204
|
+
|
205
|
+
if original_script_name
|
206
|
+
script_name = original_script_name + script_name
|
207
|
+
end
|
208
|
+
|
209
|
+
options[:script_name] = script_name
|
210
|
+
|
221
211
|
url_strategy.call options
|
222
212
|
else
|
223
213
|
super
|
@@ -225,59 +215,59 @@ module ActionDispatch
|
|
225
215
|
end
|
226
216
|
|
227
217
|
private
|
218
|
+
def optimized_helper(args)
|
219
|
+
params = parameterize_args(args) do
|
220
|
+
raise_generation_error(args)
|
221
|
+
end
|
228
222
|
|
229
|
-
|
230
|
-
params = parameterize_args(args)
|
231
|
-
missing_keys = missing_keys(params)
|
232
|
-
|
233
|
-
unless missing_keys.empty?
|
234
|
-
raise_generation_error(params, missing_keys)
|
223
|
+
@route.format params
|
235
224
|
end
|
236
225
|
|
237
|
-
|
238
|
-
|
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
|
226
|
+
def optimize_routes_generation?(t)
|
227
|
+
t.send(:optimize_routes_generation?)
|
228
|
+
end
|
249
229
|
|
250
|
-
|
251
|
-
|
252
|
-
|
230
|
+
def parameterize_args(args)
|
231
|
+
params = {}
|
232
|
+
@arg_size.times { |i|
|
233
|
+
key = @required_parts[i]
|
234
|
+
value = args[i].to_param
|
235
|
+
yield key if value.nil? || value.empty?
|
236
|
+
params[key] = value
|
237
|
+
}
|
238
|
+
params
|
239
|
+
end
|
253
240
|
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
241
|
+
def raise_generation_error(args)
|
242
|
+
missing_keys = []
|
243
|
+
params = parameterize_args(args) { |missing_key|
|
244
|
+
missing_keys << missing_key
|
245
|
+
}
|
246
|
+
constraints = Hash[@route.requirements.merge(params).sort_by { |k, v| k.to_s }]
|
247
|
+
message = +"No route matches #{constraints.inspect}"
|
248
|
+
message << ", missing required keys: #{missing_keys.sort.inspect}"
|
258
249
|
|
259
|
-
|
260
|
-
|
250
|
+
raise ActionController::UrlGenerationError, message
|
251
|
+
end
|
261
252
|
end
|
262
253
|
|
263
|
-
def initialize(route, options, route_name
|
254
|
+
def initialize(route, options, route_name)
|
264
255
|
@options = options
|
265
256
|
@segment_keys = route.segment_keys.uniq
|
266
257
|
@route = route
|
267
|
-
@url_strategy = url_strategy
|
268
258
|
@route_name = route_name
|
269
259
|
end
|
270
260
|
|
271
|
-
def call(t, args, inner_options)
|
261
|
+
def call(t, method_name, args, inner_options, url_strategy)
|
272
262
|
controller_options = t.url_options
|
273
263
|
options = controller_options.merge @options
|
274
264
|
hash = handle_positional_args(controller_options,
|
275
|
-
|
265
|
+
inner_options || {},
|
276
266
|
args,
|
277
267
|
options,
|
278
268
|
@segment_keys)
|
279
269
|
|
280
|
-
t._routes.url_for(hash, route_name, url_strategy)
|
270
|
+
t._routes.url_for(hash, route_name, url_strategy, method_name)
|
281
271
|
end
|
282
272
|
|
283
273
|
def handle_positional_args(controller_options, inner_options, args, result, path_params)
|
@@ -292,119 +282,128 @@ module ActionDispatch
|
|
292
282
|
if args.size < path_params_size
|
293
283
|
path_params -= controller_options.keys
|
294
284
|
path_params -= result.keys
|
285
|
+
else
|
286
|
+
path_params = path_params.dup
|
287
|
+
end
|
288
|
+
inner_options.each_key do |key|
|
289
|
+
path_params.delete(key)
|
295
290
|
end
|
296
|
-
path_params.each { |param|
|
297
|
-
value = inner_options.fetch(param) { args.shift }
|
298
291
|
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
|
292
|
+
args.each_with_index do |arg, index|
|
293
|
+
param = path_params[index]
|
294
|
+
result[param] = arg if param
|
295
|
+
end
|
303
296
|
end
|
304
297
|
|
305
298
|
result.merge!(inner_options)
|
306
299
|
end
|
307
|
-
|
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
|
319
|
-
end
|
320
|
-
end
|
321
|
-
options
|
322
|
-
end
|
323
300
|
end
|
324
301
|
|
325
302
|
private
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
|
334
|
-
|
335
|
-
|
336
|
-
|
337
|
-
|
338
|
-
|
339
|
-
|
340
|
-
|
341
|
-
|
342
|
-
|
343
|
-
|
344
|
-
|
345
|
-
|
303
|
+
# Create a URL helper allowing ordered parameters to be associated
|
304
|
+
# with corresponding dynamic segments, so you can do:
|
305
|
+
#
|
306
|
+
# foo_url(bar, baz, bang)
|
307
|
+
#
|
308
|
+
# Instead of:
|
309
|
+
#
|
310
|
+
# foo_url(bar: bar, baz: baz, bang: bang)
|
311
|
+
#
|
312
|
+
# Also allow options hash, so you can do:
|
313
|
+
#
|
314
|
+
# foo_url(bar, baz, bang, sort_by: 'baz')
|
315
|
+
#
|
316
|
+
def define_url_helper(mod, name, helper, url_strategy)
|
317
|
+
mod.define_method(name) do |*args|
|
318
|
+
last = args.last
|
319
|
+
options = \
|
320
|
+
case last
|
321
|
+
when Hash
|
322
|
+
args.pop
|
323
|
+
when ActionController::Parameters
|
324
|
+
args.pop.to_h
|
325
|
+
end
|
326
|
+
helper.call(self, name, args, options, url_strategy)
|
346
327
|
end
|
347
328
|
end
|
348
|
-
end
|
349
329
|
end
|
350
330
|
|
351
|
-
# strategy for building
|
331
|
+
# strategy for building URLs to send to the client
|
352
332
|
PATH = ->(options) { ActionDispatch::Http::URL.path_for(options) }
|
353
|
-
FULL = ->(options) { ActionDispatch::Http::URL.full_url_for(options) }
|
354
333
|
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
334
|
|
382
335
|
attr_accessor :formatter, :set, :named_routes, :default_scope, :router
|
383
336
|
attr_accessor :disable_clear_and_finalize, :resources_path_names
|
384
|
-
attr_accessor :default_url_options, :
|
337
|
+
attr_accessor :default_url_options, :draw_paths
|
338
|
+
attr_reader :env_key, :polymorphic_mappings
|
385
339
|
|
386
340
|
alias :routes :set
|
387
341
|
|
388
342
|
def self.default_resources_path_names
|
389
|
-
{ :
|
343
|
+
{ new: "new", edit: "edit" }
|
344
|
+
end
|
345
|
+
|
346
|
+
def self.new_with_config(config)
|
347
|
+
route_set_config = DEFAULT_CONFIG
|
348
|
+
|
349
|
+
# engines apparently don't have this set
|
350
|
+
if config.respond_to? :relative_url_root
|
351
|
+
route_set_config.relative_url_root = config.relative_url_root
|
352
|
+
end
|
353
|
+
|
354
|
+
if config.respond_to? :api_only
|
355
|
+
route_set_config.api_only = config.api_only
|
356
|
+
end
|
357
|
+
|
358
|
+
new route_set_config
|
390
359
|
end
|
391
360
|
|
392
|
-
|
361
|
+
Config = Struct.new :relative_url_root, :api_only
|
362
|
+
|
363
|
+
DEFAULT_CONFIG = Config.new(nil, false)
|
364
|
+
|
365
|
+
def initialize(config = DEFAULT_CONFIG)
|
393
366
|
self.named_routes = NamedRouteCollection.new
|
394
367
|
self.resources_path_names = self.class.default_resources_path_names
|
395
368
|
self.default_url_options = {}
|
396
|
-
self.
|
369
|
+
self.draw_paths = []
|
397
370
|
|
371
|
+
@config = config
|
398
372
|
@append = []
|
399
373
|
@prepend = []
|
400
374
|
@disable_clear_and_finalize = false
|
401
375
|
@finalized = false
|
376
|
+
@env_key = "ROUTES_#{object_id}_SCRIPT_NAME"
|
402
377
|
|
403
378
|
@set = Journey::Routes.new
|
404
379
|
@router = Journey::Router.new @set
|
405
|
-
@formatter = Journey::Formatter.new
|
380
|
+
@formatter = Journey::Formatter.new self
|
381
|
+
@polymorphic_mappings = {}
|
406
382
|
end
|
407
383
|
|
384
|
+
def eager_load!
|
385
|
+
router.eager_load!
|
386
|
+
routes.each(&:eager_load!)
|
387
|
+
nil
|
388
|
+
end
|
389
|
+
|
390
|
+
def relative_url_root
|
391
|
+
@config.relative_url_root
|
392
|
+
end
|
393
|
+
|
394
|
+
def api_only?
|
395
|
+
@config.api_only
|
396
|
+
end
|
397
|
+
|
398
|
+
def request_class
|
399
|
+
ActionDispatch::Request
|
400
|
+
end
|
401
|
+
|
402
|
+
def make_request(env)
|
403
|
+
request_class.new env
|
404
|
+
end
|
405
|
+
private :make_request
|
406
|
+
|
408
407
|
def draw(&block)
|
409
408
|
clear! unless @disable_clear_and_finalize
|
410
409
|
eval_block(block)
|
@@ -421,10 +420,6 @@ module ActionDispatch
|
|
421
420
|
end
|
422
421
|
|
423
422
|
def eval_block(block)
|
424
|
-
if block.arity == 1
|
425
|
-
raise "You are using the old router DSL which has been removed in Rails 3.1. " <<
|
426
|
-
"Please check how to update your routes file at: http://www.engineyard.com/blog/2010/the-lowdown-on-routes-in-rails-3/"
|
427
|
-
end
|
428
423
|
mapper = Mapper.new(self)
|
429
424
|
if default_scope
|
430
425
|
mapper.with_default_scope(default_scope, &block)
|
@@ -445,13 +440,10 @@ module ActionDispatch
|
|
445
440
|
named_routes.clear
|
446
441
|
set.clear
|
447
442
|
formatter.clear
|
443
|
+
@polymorphic_mappings.clear
|
448
444
|
@prepend.each { |blk| eval_block(blk) }
|
449
445
|
end
|
450
446
|
|
451
|
-
def dispatcher(defaults)
|
452
|
-
Routing::RouteSet::Dispatcher.new(defaults)
|
453
|
-
end
|
454
|
-
|
455
447
|
module MountedHelpers
|
456
448
|
extend ActiveSupport::Concern
|
457
449
|
include UrlFor
|
@@ -465,7 +457,7 @@ module ActionDispatch
|
|
465
457
|
MountedHelpers
|
466
458
|
end
|
467
459
|
|
468
|
-
def define_mounted_helper(name)
|
460
|
+
def define_mounted_helper(name, script_namer = nil)
|
469
461
|
return if MountedHelpers.method_defined?(name)
|
470
462
|
|
471
463
|
routes = self
|
@@ -473,7 +465,7 @@ module ActionDispatch
|
|
473
465
|
|
474
466
|
MountedHelpers.class_eval do
|
475
467
|
define_method "_#{name}" do
|
476
|
-
RoutesProxy.new(routes, _routes_context, helpers)
|
468
|
+
RoutesProxy.new(routes, _routes_context, helpers, script_namer)
|
477
469
|
end
|
478
470
|
end
|
479
471
|
|
@@ -485,6 +477,14 @@ module ActionDispatch
|
|
485
477
|
end
|
486
478
|
|
487
479
|
def url_helpers(supports_path = true)
|
480
|
+
if supports_path
|
481
|
+
@url_helpers_with_paths ||= generate_url_helpers(true)
|
482
|
+
else
|
483
|
+
@url_helpers_without_paths ||= generate_url_helpers(false)
|
484
|
+
end
|
485
|
+
end
|
486
|
+
|
487
|
+
def generate_url_helpers(supports_path)
|
488
488
|
routes = self
|
489
489
|
|
490
490
|
Module.new do
|
@@ -493,10 +493,50 @@ module ActionDispatch
|
|
493
493
|
|
494
494
|
# Define url_for in the singleton level so one can do:
|
495
495
|
# Rails.application.routes.url_helpers.url_for(args)
|
496
|
-
|
497
|
-
|
498
|
-
|
496
|
+
proxy_class = Class.new do
|
497
|
+
include UrlFor
|
498
|
+
include routes.named_routes.path_helpers_module
|
499
|
+
include routes.named_routes.url_helpers_module
|
500
|
+
|
499
501
|
attr_reader :_routes
|
502
|
+
|
503
|
+
def initialize(routes)
|
504
|
+
@_routes = routes
|
505
|
+
end
|
506
|
+
|
507
|
+
def optimize_routes_generation?
|
508
|
+
@_routes.optimize_routes_generation?
|
509
|
+
end
|
510
|
+
end
|
511
|
+
|
512
|
+
@_proxy = proxy_class.new(routes)
|
513
|
+
|
514
|
+
class << self
|
515
|
+
def url_for(options)
|
516
|
+
@_proxy.url_for(options)
|
517
|
+
end
|
518
|
+
|
519
|
+
def full_url_for(options)
|
520
|
+
@_proxy.full_url_for(options)
|
521
|
+
end
|
522
|
+
|
523
|
+
def route_for(name, *args)
|
524
|
+
@_proxy.route_for(name, *args)
|
525
|
+
end
|
526
|
+
|
527
|
+
def optimize_routes_generation?
|
528
|
+
@_proxy.optimize_routes_generation?
|
529
|
+
end
|
530
|
+
|
531
|
+
def polymorphic_url(record_or_hash_or_array, options = {})
|
532
|
+
@_proxy.polymorphic_url(record_or_hash_or_array, options)
|
533
|
+
end
|
534
|
+
|
535
|
+
def polymorphic_path(record_or_hash_or_array, options = {})
|
536
|
+
@_proxy.polymorphic_path(record_or_hash_or_array, options)
|
537
|
+
end
|
538
|
+
|
539
|
+
def _routes; @_proxy._routes; end
|
500
540
|
def url_options; {}; end
|
501
541
|
end
|
502
542
|
|
@@ -513,16 +553,14 @@ module ActionDispatch
|
|
513
553
|
|
514
554
|
if supports_path
|
515
555
|
path_helpers = routes.named_routes.path_helpers_module
|
516
|
-
else
|
517
|
-
path_helpers = routes.named_routes.path_helpers_module(true)
|
518
|
-
end
|
519
556
|
|
520
|
-
|
521
|
-
|
557
|
+
include path_helpers
|
558
|
+
extend path_helpers
|
559
|
+
end
|
522
560
|
|
523
561
|
# plus a singleton class method called _routes ...
|
524
562
|
included do
|
525
|
-
|
563
|
+
redefine_singleton_method(:_routes) { routes }
|
526
564
|
end
|
527
565
|
|
528
566
|
# And an instance method _routes. Note that
|
@@ -542,7 +580,7 @@ module ActionDispatch
|
|
542
580
|
routes.empty?
|
543
581
|
end
|
544
582
|
|
545
|
-
def add_route(
|
583
|
+
def add_route(mapping, name)
|
546
584
|
raise ArgumentError, "Invalid route name: '#{name}'" unless name.blank? || name.to_s.match(/^[_a-z]\w*$/i)
|
547
585
|
|
548
586
|
if name && named_routes[name]
|
@@ -550,94 +588,80 @@ module ActionDispatch
|
|
550
588
|
"You may have defined two routes with the same name using the `:as` option, or " \
|
551
589
|
"you may be overriding a route already defined by a resource with the same naming. " \
|
552
590
|
"For the latter, you can restrict the routes created with `resources` as explained here: \n" \
|
553
|
-
"
|
591
|
+
"https://guides.rubyonrails.org/routing.html#restricting-the-routes-created"
|
554
592
|
end
|
555
593
|
|
556
|
-
|
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 })
|
560
|
-
|
561
|
-
route = @set.add_route(app, path, conditions, defaults, name)
|
594
|
+
route = @set.add_route(name, mapping)
|
562
595
|
named_routes[name] = route if name
|
563
|
-
route
|
564
|
-
end
|
565
|
-
|
566
|
-
def build_path(path, ast, requirements, anchor)
|
567
|
-
strexp = Journey::Router::Strexp.new(
|
568
|
-
ast,
|
569
|
-
path,
|
570
|
-
requirements,
|
571
|
-
SEPARATORS,
|
572
|
-
anchor)
|
573
|
-
|
574
|
-
pattern = Journey::Path::Pattern.new(strexp)
|
575
596
|
|
576
|
-
|
597
|
+
if route.segment_keys.include?(:controller)
|
598
|
+
ActiveSupport::Deprecation.warn(<<-MSG.squish)
|
599
|
+
Using a dynamic :controller segment in a route is deprecated and
|
600
|
+
will be removed in Rails 6.2.
|
601
|
+
MSG
|
602
|
+
end
|
577
603
|
|
578
|
-
|
579
|
-
|
580
|
-
|
581
|
-
|
582
|
-
|
604
|
+
if route.segment_keys.include?(:action)
|
605
|
+
ActiveSupport::Deprecation.warn(<<-MSG.squish)
|
606
|
+
Using a dynamic :action segment in a route is deprecated and
|
607
|
+
will be removed in Rails 6.2.
|
608
|
+
MSG
|
609
|
+
end
|
583
610
|
|
584
|
-
|
585
|
-
|
586
|
-
builder.followpos(n).first
|
587
|
-
}.find_all(&:symbol?)
|
611
|
+
route
|
612
|
+
end
|
588
613
|
|
589
|
-
|
590
|
-
|
591
|
-
|
614
|
+
def add_polymorphic_mapping(klass, options, &block)
|
615
|
+
@polymorphic_mappings[klass] = CustomUrlHelper.new(klass, options, &block)
|
616
|
+
end
|
592
617
|
|
593
|
-
|
618
|
+
def add_url_helper(name, options, &block)
|
619
|
+
named_routes.add_url_helper(name, options, &block)
|
594
620
|
end
|
595
|
-
private :build_path
|
596
621
|
|
597
|
-
|
598
|
-
|
622
|
+
class CustomUrlHelper
|
623
|
+
attr_reader :name, :defaults, :block
|
599
624
|
|
600
|
-
|
601
|
-
|
602
|
-
|
603
|
-
|
604
|
-
verbs = conditions[:request_method] || []
|
605
|
-
unless verbs.empty?
|
606
|
-
conditions[:request_method] = %r[^#{verbs.join('|')}$]
|
625
|
+
def initialize(name, defaults, &block)
|
626
|
+
@name = name
|
627
|
+
@defaults = defaults
|
628
|
+
@block = block
|
607
629
|
end
|
608
630
|
|
609
|
-
|
610
|
-
|
611
|
-
|
612
|
-
end
|
613
|
-
end
|
614
|
-
private :build_conditions
|
631
|
+
def call(t, args, only_path = false)
|
632
|
+
options = args.extract_options!
|
633
|
+
url = t.full_url_for(eval_block(t, args, options))
|
615
634
|
|
616
|
-
|
617
|
-
|
618
|
-
|
619
|
-
|
620
|
-
elsif value.is_a?(Array)
|
621
|
-
value.map { |v| v.to_param }.join('/')
|
622
|
-
elsif param = value.to_param
|
623
|
-
param
|
635
|
+
if only_path
|
636
|
+
"/" + url.partition(%r{(?<!/)/(?!/)}).last
|
637
|
+
else
|
638
|
+
url
|
624
639
|
end
|
625
640
|
end
|
626
641
|
|
642
|
+
private
|
643
|
+
def eval_block(t, args, options)
|
644
|
+
t.instance_exec(*args, merge_defaults(options), &block)
|
645
|
+
end
|
646
|
+
|
647
|
+
def merge_defaults(options)
|
648
|
+
defaults ? defaults.merge(options) : options
|
649
|
+
end
|
650
|
+
end
|
651
|
+
|
652
|
+
class Generator
|
627
653
|
attr_reader :options, :recall, :set, :named_route
|
628
654
|
|
629
655
|
def initialize(named_route, options, recall, set)
|
630
656
|
@named_route = named_route
|
631
|
-
@options = options
|
632
|
-
@recall = recall
|
657
|
+
@options = options
|
658
|
+
@recall = recall
|
633
659
|
@set = set
|
634
660
|
|
635
|
-
normalize_recall!
|
636
661
|
normalize_options!
|
637
662
|
normalize_controller_action_id!
|
638
663
|
use_relative_controller!
|
639
664
|
normalize_controller!
|
640
|
-
normalize_action!
|
641
665
|
end
|
642
666
|
|
643
667
|
def controller
|
@@ -651,16 +675,11 @@ module ActionDispatch
|
|
651
675
|
def use_recall_for(key)
|
652
676
|
if @recall[key] && (!@options.key?(key) || @options[key] == @recall[key])
|
653
677
|
if !named_route_exists? || segment_keys.include?(key)
|
654
|
-
@options[key] = @recall
|
678
|
+
@options[key] = @recall[key]
|
655
679
|
end
|
656
680
|
end
|
657
681
|
end
|
658
682
|
|
659
|
-
# Set 'index' as default action for recall
|
660
|
-
def normalize_recall!
|
661
|
-
@recall[:action] ||= 'index'
|
662
|
-
end
|
663
|
-
|
664
683
|
def normalize_options!
|
665
684
|
# If an explicit :controller was given, always make :action explicit
|
666
685
|
# too, so that action expiry works as expected for things like
|
@@ -672,12 +691,12 @@ module ActionDispatch
|
|
672
691
|
# be "index", not the recalled action of "show".
|
673
692
|
|
674
693
|
if options[:controller]
|
675
|
-
options[:action] ||=
|
694
|
+
options[:action] ||= "index"
|
676
695
|
options[:controller] = options[:controller].to_s
|
677
696
|
end
|
678
697
|
|
679
698
|
if options.key?(:action)
|
680
|
-
options[:action] = (options[:action] ||
|
699
|
+
options[:action] = (options[:action] || "index").to_s
|
681
700
|
end
|
682
701
|
end
|
683
702
|
|
@@ -687,8 +706,8 @@ module ActionDispatch
|
|
687
706
|
# :controller, :action or :id is not found, don't pull any
|
688
707
|
# more keys from the recall.
|
689
708
|
def normalize_controller_action_id!
|
690
|
-
use_recall_for(:controller)
|
691
|
-
use_recall_for(:action)
|
709
|
+
use_recall_for(:controller) || return
|
710
|
+
use_recall_for(:action) || return
|
692
711
|
use_recall_for(:id)
|
693
712
|
end
|
694
713
|
|
@@ -696,7 +715,7 @@ module ActionDispatch
|
|
696
715
|
# is specified, the controller becomes "foo/baz/bat"
|
697
716
|
def use_relative_controller!
|
698
717
|
if !named_route && different_controller? && !controller.start_with?("/")
|
699
|
-
old_parts = current_controller.split(
|
718
|
+
old_parts = current_controller.split("/")
|
700
719
|
size = controller.count("/") + 1
|
701
720
|
parts = old_parts[0...-size] << controller
|
702
721
|
@options[:controller] = parts.join("/")
|
@@ -705,20 +724,19 @@ module ActionDispatch
|
|
705
724
|
|
706
725
|
# Remove leading slashes from controllers
|
707
726
|
def normalize_controller!
|
708
|
-
|
709
|
-
|
710
|
-
|
711
|
-
|
712
|
-
|
713
|
-
|
714
|
-
@recall[:action] = @options.delete(:action)
|
727
|
+
if controller
|
728
|
+
if controller.start_with?("/")
|
729
|
+
@options[:controller] = controller[1..-1]
|
730
|
+
else
|
731
|
+
@options[:controller] = controller
|
732
|
+
end
|
715
733
|
end
|
716
734
|
end
|
717
735
|
|
718
|
-
# Generates a path from routes, returns
|
719
|
-
#
|
736
|
+
# Generates a path from routes, returns a RouteWithParams or MissingRoute.
|
737
|
+
# MissingRoute will raise ActionController::UrlGenerationError.
|
720
738
|
def generate
|
721
|
-
@set.formatter.generate(named_route, options, recall
|
739
|
+
@set.formatter.generate(named_route, options, recall)
|
722
740
|
end
|
723
741
|
|
724
742
|
def different_controller?
|
@@ -738,18 +756,23 @@ module ActionDispatch
|
|
738
756
|
|
739
757
|
# Generate the path indicated by the arguments, and return an array of
|
740
758
|
# the keys that were not used to generate it.
|
741
|
-
def extra_keys(options, recall={})
|
759
|
+
def extra_keys(options, recall = {})
|
742
760
|
generate_extras(options, recall).last
|
743
761
|
end
|
744
762
|
|
745
|
-
def generate_extras(options, recall={})
|
746
|
-
|
747
|
-
|
748
|
-
|
763
|
+
def generate_extras(options, recall = {})
|
764
|
+
if recall
|
765
|
+
options = options.merge(_recall: recall)
|
766
|
+
end
|
767
|
+
|
768
|
+
route_name = options.delete :use_route
|
769
|
+
generator = generate(route_name, options, recall)
|
770
|
+
path_info = path_for(options, route_name, [])
|
771
|
+
[URI(path_info).path, generator.params.except(:_recall).keys]
|
749
772
|
end
|
750
773
|
|
751
|
-
def generate(
|
752
|
-
Generator.new(
|
774
|
+
def generate(route_name, options, recall = {}, method_name = nil)
|
775
|
+
Generator.new(route_name, options, recall, self).generate
|
753
776
|
end
|
754
777
|
private :generate
|
755
778
|
|
@@ -762,19 +785,19 @@ module ActionDispatch
|
|
762
785
|
end
|
763
786
|
|
764
787
|
def find_script_name(options)
|
765
|
-
options.delete(:script_name) || find_relative_url_root(options) ||
|
788
|
+
options.delete(:script_name) || find_relative_url_root(options) || ""
|
766
789
|
end
|
767
790
|
|
768
791
|
def find_relative_url_root(options)
|
769
792
|
options.delete(:relative_url_root) || relative_url_root
|
770
793
|
end
|
771
794
|
|
772
|
-
def path_for(options, route_name = nil)
|
773
|
-
url_for(options, route_name, PATH)
|
795
|
+
def path_for(options, route_name = nil, reserved = RESERVED_OPTIONS)
|
796
|
+
url_for(options, route_name, PATH, nil, reserved)
|
774
797
|
end
|
775
798
|
|
776
799
|
# The +options+ argument must be a hash whose keys are *symbols*.
|
777
|
-
def url_for(options, route_name = nil, url_strategy = UNKNOWN)
|
800
|
+
def url_for(options, route_name = nil, url_strategy = UNKNOWN, method_name = nil, reserved = RESERVED_OPTIONS)
|
778
801
|
options = default_url_options.merge options
|
779
802
|
|
780
803
|
user = password = nil
|
@@ -784,7 +807,7 @@ module ActionDispatch
|
|
784
807
|
password = options.delete :password
|
785
808
|
end
|
786
809
|
|
787
|
-
recall
|
810
|
+
recall = options.delete(:_recall) { {} }
|
788
811
|
|
789
812
|
original_script_name = options.delete(:original_script_name)
|
790
813
|
script_name = find_script_name options
|
@@ -794,9 +817,11 @@ module ActionDispatch
|
|
794
817
|
end
|
795
818
|
|
796
819
|
path_options = options.dup
|
797
|
-
|
820
|
+
reserved.each { |ro| path_options.delete ro }
|
798
821
|
|
799
|
-
|
822
|
+
route_with_params = generate(route_name, path_options, recall)
|
823
|
+
path = route_with_params.path(method_name)
|
824
|
+
params = route_with_params.params
|
800
825
|
|
801
826
|
if options.key? :params
|
802
827
|
params.merge! options[:params]
|
@@ -812,47 +837,54 @@ module ActionDispatch
|
|
812
837
|
end
|
813
838
|
|
814
839
|
def call(env)
|
815
|
-
req =
|
840
|
+
req = make_request(env)
|
816
841
|
req.path_info = Journey::Router::Utils.normalize_path(req.path_info)
|
817
842
|
@router.serve(req)
|
818
843
|
end
|
819
844
|
|
820
845
|
def recognize_path(path, environment = {})
|
821
846
|
method = (environment[:method] || "GET").to_s.upcase
|
822
|
-
path = Journey::Router::Utils.normalize_path(path) unless
|
847
|
+
path = Journey::Router::Utils.normalize_path(path) unless %r{://}.match?(path)
|
823
848
|
extras = environment[:extras] || {}
|
824
849
|
|
825
850
|
begin
|
826
|
-
env = Rack::MockRequest.env_for(path,
|
851
|
+
env = Rack::MockRequest.env_for(path, method: method)
|
827
852
|
rescue URI::InvalidURIError => e
|
828
853
|
raise ActionController::RoutingError, e.message
|
829
854
|
end
|
830
855
|
|
831
|
-
req =
|
856
|
+
req = make_request(env)
|
857
|
+
recognize_path_with_request(req, path, extras)
|
858
|
+
end
|
859
|
+
|
860
|
+
def recognize_path_with_request(req, path, extras, raise_on_missing: true)
|
832
861
|
@router.recognize(req) do |route, params|
|
833
862
|
params.merge!(extras)
|
834
863
|
params.each do |key, value|
|
835
864
|
if value.is_a?(String)
|
836
865
|
value = value.dup.force_encoding(Encoding::BINARY)
|
837
|
-
params[key] = URI.
|
866
|
+
params[key] = URI::DEFAULT_PARSER.unescape(value)
|
838
867
|
end
|
839
868
|
end
|
840
|
-
|
841
|
-
req.path_parameters = old_params.merge params
|
869
|
+
req.path_parameters = params
|
842
870
|
app = route.app
|
843
871
|
if app.matches?(req) && app.dispatcher?
|
844
|
-
|
845
|
-
|
846
|
-
|
847
|
-
dispatcher.prepare_params!(params)
|
848
|
-
return params
|
849
|
-
else
|
872
|
+
begin
|
873
|
+
req.controller_class
|
874
|
+
rescue NameError
|
850
875
|
raise ActionController::RoutingError, "A route matches #{path.inspect}, but references missing controller: #{params[:controller].camelize}Controller"
|
851
876
|
end
|
877
|
+
|
878
|
+
return req.path_parameters
|
879
|
+
elsif app.matches?(req) && app.engine?
|
880
|
+
path_parameters = app.rack_app.routes.recognize_path_with_request(req, path, extras, raise_on_missing: false)
|
881
|
+
return path_parameters if path_parameters
|
852
882
|
end
|
853
883
|
end
|
854
884
|
|
855
|
-
|
885
|
+
if raise_on_missing
|
886
|
+
raise ActionController::RoutingError, "No route matches #{path.inspect}"
|
887
|
+
end
|
856
888
|
end
|
857
889
|
end
|
858
890
|
# :startdoc:
|