actionpack 6.0.6.1 → 6.1.0.rc1
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 +232 -354
- data/MIT-LICENSE +1 -1
- data/README.rdoc +1 -1
- data/lib/abstract_controller/base.rb +35 -2
- data/lib/abstract_controller/callbacks.rb +2 -2
- data/lib/abstract_controller/helpers.rb +105 -90
- data/lib/abstract_controller/rendering.rb +9 -9
- data/lib/abstract_controller/translation.rb +8 -2
- data/lib/abstract_controller.rb +1 -0
- data/lib/action_controller/api.rb +2 -2
- data/lib/action_controller/base.rb +4 -2
- data/lib/action_controller/caching.rb +0 -1
- data/lib/action_controller/log_subscriber.rb +3 -3
- data/lib/action_controller/metal/conditional_get.rb +10 -2
- data/lib/action_controller/metal/content_security_policy.rb +1 -1
- data/lib/action_controller/metal/data_streaming.rb +1 -1
- data/lib/action_controller/metal/etag_with_template_digest.rb +2 -4
- data/lib/action_controller/metal/exceptions.rb +33 -0
- data/lib/action_controller/metal/feature_policy.rb +46 -0
- data/lib/action_controller/metal/head.rb +7 -4
- data/lib/action_controller/metal/helpers.rb +11 -1
- data/lib/action_controller/metal/http_authentication.rb +5 -3
- data/lib/action_controller/metal/implicit_render.rb +1 -1
- data/lib/action_controller/metal/instrumentation.rb +11 -9
- data/lib/action_controller/metal/live.rb +1 -1
- data/lib/action_controller/metal/logging.rb +20 -0
- data/lib/action_controller/metal/mime_responds.rb +6 -2
- data/lib/action_controller/metal/parameter_encoding.rb +35 -4
- data/lib/action_controller/metal/params_wrapper.rb +16 -11
- data/lib/action_controller/metal/redirecting.rb +1 -1
- data/lib/action_controller/metal/rendering.rb +6 -0
- data/lib/action_controller/metal/request_forgery_protection.rb +1 -1
- data/lib/action_controller/metal/rescue.rb +1 -1
- data/lib/action_controller/metal/strong_parameters.rb +103 -15
- data/lib/action_controller/metal.rb +2 -2
- data/lib/action_controller/renderer.rb +23 -13
- data/lib/action_controller/test_case.rb +62 -56
- data/lib/action_controller.rb +2 -3
- data/lib/action_dispatch/http/cache.rb +12 -10
- data/lib/action_dispatch/http/content_security_policy.rb +11 -0
- data/lib/action_dispatch/http/feature_policy.rb +168 -0
- data/lib/action_dispatch/http/filter_parameters.rb +1 -1
- data/lib/action_dispatch/http/filter_redirect.rb +1 -1
- data/lib/action_dispatch/http/headers.rb +3 -2
- data/lib/action_dispatch/http/mime_negotiation.rb +14 -8
- data/lib/action_dispatch/http/mime_type.rb +29 -16
- data/lib/action_dispatch/http/parameters.rb +1 -19
- data/lib/action_dispatch/http/request.rb +24 -8
- data/lib/action_dispatch/http/response.rb +17 -16
- data/lib/action_dispatch/http/url.rb +3 -2
- data/lib/action_dispatch/journey/formatter.rb +53 -28
- data/lib/action_dispatch/journey/gtg/builder.rb +22 -36
- data/lib/action_dispatch/journey/gtg/simulator.rb +8 -7
- data/lib/action_dispatch/journey/gtg/transition_table.rb +6 -4
- data/lib/action_dispatch/journey/nfa/dot.rb +0 -11
- data/lib/action_dispatch/journey/nodes/node.rb +4 -3
- data/lib/action_dispatch/journey/parser.rb +13 -13
- data/lib/action_dispatch/journey/parser.y +1 -1
- data/lib/action_dispatch/journey/path/pattern.rb +13 -18
- data/lib/action_dispatch/journey/route.rb +7 -18
- data/lib/action_dispatch/journey/router/utils.rb +6 -4
- data/lib/action_dispatch/journey/router.rb +26 -30
- data/lib/action_dispatch/journey.rb +0 -2
- data/lib/action_dispatch/middleware/actionable_exceptions.rb +1 -1
- data/lib/action_dispatch/middleware/cookies.rb +67 -32
- data/lib/action_dispatch/middleware/debug_exceptions.rb +8 -15
- data/lib/action_dispatch/middleware/debug_view.rb +1 -1
- data/lib/action_dispatch/middleware/exception_wrapper.rb +28 -16
- data/lib/action_dispatch/middleware/executor.rb +1 -1
- data/lib/action_dispatch/middleware/host_authorization.rb +35 -35
- data/lib/action_dispatch/middleware/remote_ip.rb +5 -4
- data/lib/action_dispatch/middleware/request_id.rb +4 -5
- data/lib/action_dispatch/middleware/session/abstract_store.rb +2 -2
- data/lib/action_dispatch/middleware/session/cookie_store.rb +2 -2
- data/lib/action_dispatch/middleware/ssl.rb +9 -6
- data/lib/action_dispatch/middleware/stack.rb +18 -0
- data/lib/action_dispatch/middleware/static.rb +154 -93
- data/lib/action_dispatch/middleware/templates/rescues/_message_and_suggestions.html.erb +18 -0
- data/lib/action_dispatch/middleware/templates/rescues/blocked_host.html.erb +1 -1
- data/lib/action_dispatch/middleware/templates/rescues/blocked_host.text.erb +1 -1
- data/lib/action_dispatch/middleware/templates/rescues/diagnostics.html.erb +2 -5
- data/lib/action_dispatch/middleware/templates/rescues/invalid_statement.html.erb +2 -2
- data/lib/action_dispatch/middleware/templates/rescues/invalid_statement.text.erb +2 -3
- data/lib/action_dispatch/middleware/templates/rescues/layout.erb +88 -8
- data/lib/action_dispatch/middleware/templates/rescues/unknown_action.html.erb +1 -1
- data/lib/action_dispatch/middleware/templates/routes/_table.html.erb +12 -1
- data/lib/action_dispatch/railtie.rb +3 -2
- data/lib/action_dispatch/request/session.rb +2 -8
- data/lib/action_dispatch/request/utils.rb +26 -2
- data/lib/action_dispatch/routing/inspector.rb +8 -7
- data/lib/action_dispatch/routing/mapper.rb +102 -71
- data/lib/action_dispatch/routing/polymorphic_routes.rb +16 -19
- data/lib/action_dispatch/routing/redirection.rb +3 -3
- data/lib/action_dispatch/routing/route_set.rb +49 -41
- data/lib/action_dispatch/system_test_case.rb +29 -24
- data/lib/action_dispatch/system_testing/browser.rb +33 -27
- data/lib/action_dispatch/system_testing/driver.rb +6 -7
- data/lib/action_dispatch/system_testing/test_helpers/screenshot_helper.rb +47 -6
- data/lib/action_dispatch/system_testing/test_helpers/setup_and_teardown.rb +4 -7
- data/lib/action_dispatch/testing/assertions/response.rb +2 -4
- data/lib/action_dispatch/testing/assertions/routing.rb +5 -5
- data/lib/action_dispatch/testing/assertions.rb +1 -1
- data/lib/action_dispatch/testing/integration.rb +38 -27
- data/lib/action_dispatch/testing/test_process.rb +29 -4
- data/lib/action_dispatch/testing/test_request.rb +3 -3
- data/lib/action_dispatch.rb +3 -2
- data/lib/action_pack/gem_version.rb +3 -3
- data/lib/action_pack.rb +1 -1
- metadata +23 -25
- data/lib/action_controller/metal/force_ssl.rb +0 -58
- data/lib/action_dispatch/http/parameter_filter.rb +0 -12
- data/lib/action_dispatch/journey/nfa/builder.rb +0 -78
- data/lib/action_dispatch/journey/nfa/simulator.rb +0 -47
- data/lib/action_dispatch/journey/nfa/transition_table.rb +0 -119
@@ -4,6 +4,7 @@ require "active_support/core_ext/hash/slice"
|
|
4
4
|
require "active_support/core_ext/enumerable"
|
5
5
|
require "active_support/core_ext/array/extract_options"
|
6
6
|
require "active_support/core_ext/regexp"
|
7
|
+
require "active_support/core_ext/symbol/starts_ends_with"
|
7
8
|
require "action_dispatch/routing/redirection"
|
8
9
|
require "action_dispatch/routing/endpoint"
|
9
10
|
|
@@ -74,13 +75,17 @@ module ActionDispatch
|
|
74
75
|
:default_action, :required_defaults, :ast, :scope_options
|
75
76
|
|
76
77
|
def self.build(scope, set, ast, controller, default_action, to, via, formatted, options_constraints, anchor, options)
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
78
|
+
scope_params = {
|
79
|
+
blocks: scope[:blocks] || [],
|
80
|
+
constraints: scope[:constraints] || {},
|
81
|
+
defaults: (scope[:defaults] || {}).dup,
|
82
|
+
module: scope[:module],
|
83
|
+
options: scope[:options] || {}
|
84
|
+
}
|
82
85
|
|
83
|
-
new set, ast
|
86
|
+
new set: set, ast: ast, controller: controller, default_action: default_action,
|
87
|
+
to: to, formatted: formatted, via: via, options_constraints: options_constraints,
|
88
|
+
anchor: anchor, scope_params: scope_params, options: scope_params[:options].merge(options)
|
84
89
|
end
|
85
90
|
|
86
91
|
def self.check_via(via)
|
@@ -108,13 +113,12 @@ module ActionDispatch
|
|
108
113
|
end
|
109
114
|
|
110
115
|
def self.optional_format?(path, format)
|
111
|
-
format != false && path
|
116
|
+
format != false && !path.match?(OPTIONAL_FORMAT_REGEX)
|
112
117
|
end
|
113
118
|
|
114
|
-
def initialize(set
|
115
|
-
@defaults
|
116
|
-
@set
|
117
|
-
|
119
|
+
def initialize(set:, ast:, controller:, default_action:, to:, formatted:, via:, options_constraints:, anchor:, scope_params:, options:)
|
120
|
+
@defaults = scope_params[:defaults]
|
121
|
+
@set = set
|
118
122
|
@to = intern(to)
|
119
123
|
@default_controller = intern(controller)
|
120
124
|
@default_action = intern(default_action)
|
@@ -122,23 +126,35 @@ module ActionDispatch
|
|
122
126
|
@anchor = anchor
|
123
127
|
@via = via
|
124
128
|
@internal = options.delete(:internal)
|
125
|
-
@scope_options =
|
126
|
-
|
127
|
-
path_params =
|
129
|
+
@scope_options = scope_params[:options]
|
130
|
+
|
131
|
+
path_params = []
|
132
|
+
wildcard_options = {}
|
133
|
+
ast.each do |node|
|
134
|
+
if node.symbol?
|
135
|
+
path_params << node.to_sym
|
136
|
+
elsif formatted != false && node.star?
|
137
|
+
# Add a constraint for wildcard route to make it non-greedy and match the
|
138
|
+
# optional format part of the route by default.
|
139
|
+
wildcard_options[node.name.to_sym] ||= /.+?/
|
140
|
+
elsif node.cat?
|
141
|
+
alter_regex_for_custom_routes(node)
|
142
|
+
end
|
143
|
+
end
|
128
144
|
|
129
|
-
options =
|
145
|
+
options = wildcard_options.merge!(options)
|
130
146
|
|
131
|
-
options = normalize_options!(options, path_params,
|
147
|
+
options = normalize_options!(options, path_params, scope_params[:module])
|
132
148
|
|
133
149
|
split_options = constraints(options, path_params)
|
134
150
|
|
135
|
-
constraints =
|
151
|
+
constraints = scope_params[:constraints].merge Hash[split_options[:constraints] || []]
|
136
152
|
|
137
153
|
if options_constraints.is_a?(Hash)
|
138
154
|
@defaults = Hash[options_constraints.find_all { |key, default|
|
139
155
|
URL_OPTIONS.include?(key) && (String === default || Integer === default)
|
140
156
|
}].merge @defaults
|
141
|
-
@blocks = blocks
|
157
|
+
@blocks = scope_params[:blocks]
|
142
158
|
constraints.merge! options_constraints
|
143
159
|
else
|
144
160
|
@blocks = blocks(options_constraints)
|
@@ -161,16 +177,20 @@ module ActionDispatch
|
|
161
177
|
end
|
162
178
|
|
163
179
|
def make_route(name, precedence)
|
164
|
-
Journey::Route.new(name, application, path, conditions,
|
165
|
-
|
180
|
+
Journey::Route.new(name: name, app: application, path: path, constraints: conditions,
|
181
|
+
required_defaults: required_defaults, defaults: defaults,
|
182
|
+
request_method_match: request_method, precedence: precedence,
|
183
|
+
scope_options: scope_options, internal: @internal)
|
166
184
|
end
|
167
185
|
|
168
186
|
def application
|
169
187
|
app(@blocks)
|
170
188
|
end
|
171
189
|
|
190
|
+
JOINED_SEPARATORS = SEPARATORS.join # :nodoc:
|
191
|
+
|
172
192
|
def path
|
173
|
-
|
193
|
+
Journey::Path::Pattern.new(@ast, requirements, JOINED_SEPARATORS, @anchor)
|
174
194
|
end
|
175
195
|
|
176
196
|
def conditions
|
@@ -191,16 +211,10 @@ module ActionDispatch
|
|
191
211
|
end
|
192
212
|
private :request_method
|
193
213
|
|
194
|
-
|
195
|
-
|
196
|
-
def build_path(ast, requirements, anchor)
|
197
|
-
pattern = Journey::Path::Pattern.new(ast, requirements, JOINED_SEPARATORS, anchor)
|
198
|
-
|
214
|
+
private
|
199
215
|
# Find all the symbol nodes that are adjacent to literal nodes and alter
|
200
216
|
# the regexp so that Journey will partition them into custom routes.
|
201
|
-
|
202
|
-
next unless node.cat?
|
203
|
-
|
217
|
+
def alter_regex_for_custom_routes(node)
|
204
218
|
if node.left.literal? && node.right.symbol?
|
205
219
|
symbol = node.right
|
206
220
|
elsif node.left.literal? && node.right.cat? && node.right.left.symbol?
|
@@ -209,36 +223,17 @@ module ActionDispatch
|
|
209
223
|
symbol = node.left
|
210
224
|
elsif node.left.symbol? && node.right.cat? && node.right.left.literal?
|
211
225
|
symbol = node.left
|
212
|
-
else
|
213
|
-
next
|
214
226
|
end
|
215
227
|
|
216
228
|
if symbol
|
217
229
|
symbol.regexp = /(?:#{Regexp.union(symbol.regexp, '-')})+/
|
218
230
|
end
|
219
|
-
|
220
|
-
|
221
|
-
pattern
|
222
|
-
end
|
223
|
-
private :build_path
|
231
|
+
end
|
224
232
|
|
225
|
-
private
|
226
233
|
def intern(object)
|
227
234
|
object.is_a?(String) ? -object : object
|
228
235
|
end
|
229
236
|
|
230
|
-
def add_wildcard_options(options, formatted, path_ast)
|
231
|
-
# Add a constraint for wildcard route to make it non-greedy and match the
|
232
|
-
# optional format part of the route by default.
|
233
|
-
if formatted != false
|
234
|
-
path_ast.grep(Journey::Nodes::Star).each_with_object({}) { |node, hash|
|
235
|
-
hash[node.name.to_sym] ||= /.+?/
|
236
|
-
}.merge options
|
237
|
-
else
|
238
|
-
options
|
239
|
-
end
|
240
|
-
end
|
241
|
-
|
242
237
|
def normalize_options!(options, path_params, modyoule)
|
243
238
|
if path_params.include?(:controller)
|
244
239
|
raise ArgumentError, ":controller segment is not allowed within a namespace block" if modyoule
|
@@ -342,7 +337,7 @@ module ActionDispatch
|
|
342
337
|
|
343
338
|
def split_to(to)
|
344
339
|
if /#/.match?(to)
|
345
|
-
to.split("#")
|
340
|
+
to.split("#").map!(&:-@)
|
346
341
|
else
|
347
342
|
[]
|
348
343
|
end
|
@@ -350,10 +345,10 @@ module ActionDispatch
|
|
350
345
|
|
351
346
|
def add_controller_module(controller, modyoule)
|
352
347
|
if modyoule && !controller.is_a?(Regexp)
|
353
|
-
if
|
354
|
-
controller[1..-1]
|
348
|
+
if controller&.start_with?("/")
|
349
|
+
-controller[1..-1]
|
355
350
|
else
|
356
|
-
[modyoule, controller].compact.join("/")
|
351
|
+
-[modyoule, controller].compact.join("/")
|
357
352
|
end
|
358
353
|
else
|
359
354
|
controller
|
@@ -393,12 +388,23 @@ module ActionDispatch
|
|
393
388
|
end
|
394
389
|
end
|
395
390
|
|
396
|
-
# Invokes Journey::Router::Utils.normalize_path
|
397
|
-
# (:locale) becomes (/:locale)
|
398
|
-
#
|
391
|
+
# Invokes Journey::Router::Utils.normalize_path, then ensures that
|
392
|
+
# /(:locale) becomes (/:locale). Except for root cases, where the
|
393
|
+
# former is the correct one.
|
399
394
|
def self.normalize_path(path)
|
400
395
|
path = Journey::Router::Utils.normalize_path(path)
|
401
|
-
|
396
|
+
|
397
|
+
# the path for a root URL at this point can be something like
|
398
|
+
# "/(/:locale)(/:platform)/(:browser)", and we would want
|
399
|
+
# "/(:locale)(/:platform)(/:browser)"
|
400
|
+
|
401
|
+
# reverse "/(", "/((" etc to "(/", "((/" etc
|
402
|
+
path.gsub!(%r{/(\(+)/?}, '\1/')
|
403
|
+
# if a path is all optional segments, change the leading "(/" back to
|
404
|
+
# "/(" so it evaluates to "/" when interpreted with no options.
|
405
|
+
# Unless, however, at least one secondary segment consists of a static
|
406
|
+
# part, ex. "(/:locale)(/pages/:page)"
|
407
|
+
path.sub!(%r{^(\(+)/}, '/\1') if %r{^(\(+[^)]+\))(\(+/:[^)]+\))*$}.match?(path)
|
402
408
|
path
|
403
409
|
end
|
404
410
|
|
@@ -555,7 +561,7 @@ module ActionDispatch
|
|
555
561
|
# Constrains parameters with a hash of regular expressions
|
556
562
|
# or an object that responds to <tt>matches?</tt>. In addition, constraints
|
557
563
|
# other than path can also be specified with any object
|
558
|
-
# that responds to <tt>===</tt> (
|
564
|
+
# that responds to <tt>===</tt> (e.g. String, Array, Range, etc.).
|
559
565
|
#
|
560
566
|
# match 'path/:id', constraints: { id: /[A-Z]\d{5}/ }, via: :get
|
561
567
|
#
|
@@ -684,7 +690,7 @@ module ActionDispatch
|
|
684
690
|
|
685
691
|
# We must actually delete prefix segment keys to avoid passing them to next url_for.
|
686
692
|
_route.segment_keys.each { |k| options.delete(k) }
|
687
|
-
_url_helpers.
|
693
|
+
_url_helpers.public_send("#{name}_path", prefix_options)
|
688
694
|
end
|
689
695
|
|
690
696
|
app.routes.define_mounted_helper(name, script_namer)
|
@@ -744,6 +750,14 @@ module ActionDispatch
|
|
744
750
|
map_method(:delete, args, &block)
|
745
751
|
end
|
746
752
|
|
753
|
+
# Define a route that only recognizes HTTP OPTIONS.
|
754
|
+
# For supported arguments, see match[rdoc-ref:Base#match]
|
755
|
+
#
|
756
|
+
# options 'carrots', to: 'food#carrots'
|
757
|
+
def options(*args, &block)
|
758
|
+
map_method(:options, args, &block)
|
759
|
+
end
|
760
|
+
|
747
761
|
private
|
748
762
|
def map_method(method, args, &block)
|
749
763
|
options = args.extract_options!
|
@@ -991,7 +1005,7 @@ module ActionDispatch
|
|
991
1005
|
#
|
992
1006
|
# Requests to routes can be constrained based on specific criteria:
|
993
1007
|
#
|
994
|
-
# constraints(-> (req) { req.env["HTTP_USER_AGENT"]
|
1008
|
+
# constraints(-> (req) { /iPhone/.match?(req.env["HTTP_USER_AGENT"]) }) do
|
995
1009
|
# resources :iphones
|
996
1010
|
# end
|
997
1011
|
#
|
@@ -1001,7 +1015,7 @@ module ActionDispatch
|
|
1001
1015
|
#
|
1002
1016
|
# class Iphone
|
1003
1017
|
# def self.matches?(request)
|
1004
|
-
# request.env["HTTP_USER_AGENT"]
|
1018
|
+
# /iPhone/.match?(request.env["HTTP_USER_AGENT"])
|
1005
1019
|
# end
|
1006
1020
|
# end
|
1007
1021
|
#
|
@@ -1594,6 +1608,22 @@ module ActionDispatch
|
|
1594
1608
|
!parent_resource.singleton? && @scope[:shallow]
|
1595
1609
|
end
|
1596
1610
|
|
1611
|
+
def draw(name)
|
1612
|
+
path = @draw_paths.find do |_path|
|
1613
|
+
File.exist? "#{_path}/#{name}.rb"
|
1614
|
+
end
|
1615
|
+
|
1616
|
+
unless path
|
1617
|
+
msg = "Your router tried to #draw the external file #{name}.rb,\n" \
|
1618
|
+
"but the file was not found in:\n\n"
|
1619
|
+
msg += @draw_paths.map { |_path| " * #{_path}" }.join("\n")
|
1620
|
+
raise ArgumentError, msg
|
1621
|
+
end
|
1622
|
+
|
1623
|
+
route_path = "#{path}/#{name}.rb"
|
1624
|
+
instance_eval(File.read(route_path), route_path.to_s)
|
1625
|
+
end
|
1626
|
+
|
1597
1627
|
# Matches a URL pattern to one or more routes.
|
1598
1628
|
# For more information, see match[rdoc-ref:Base#match].
|
1599
1629
|
#
|
@@ -1674,20 +1704,20 @@ module ActionDispatch
|
|
1674
1704
|
|
1675
1705
|
def apply_common_behavior_for(method, resources, options, &block)
|
1676
1706
|
if resources.length > 1
|
1677
|
-
resources.each { |r|
|
1707
|
+
resources.each { |r| public_send(method, r, options, &block) }
|
1678
1708
|
return true
|
1679
1709
|
end
|
1680
1710
|
|
1681
1711
|
if options[:shallow]
|
1682
1712
|
options.delete(:shallow)
|
1683
1713
|
shallow do
|
1684
|
-
|
1714
|
+
public_send(method, resources.pop, options, &block)
|
1685
1715
|
end
|
1686
1716
|
return true
|
1687
1717
|
end
|
1688
1718
|
|
1689
1719
|
if resource_scope?
|
1690
|
-
nested {
|
1720
|
+
nested { public_send(method, resources.pop, options, &block) }
|
1691
1721
|
return true
|
1692
1722
|
end
|
1693
1723
|
|
@@ -1698,7 +1728,7 @@ module ActionDispatch
|
|
1698
1728
|
scope_options = options.slice!(*RESOURCE_OPTIONS)
|
1699
1729
|
unless scope_options.empty?
|
1700
1730
|
scope(scope_options) do
|
1701
|
-
|
1731
|
+
public_send(method, resources.pop, options, &block)
|
1702
1732
|
end
|
1703
1733
|
return true
|
1704
1734
|
end
|
@@ -1828,7 +1858,7 @@ module ActionDispatch
|
|
1828
1858
|
# and return nil in case it isn't. Otherwise, we pass the invalid name
|
1829
1859
|
# forward so the underlying router engine treats it and raises an exception.
|
1830
1860
|
if as.nil?
|
1831
|
-
candidate unless candidate
|
1861
|
+
candidate unless !candidate.match?(/\A[_a-z]/i) || has_named_route?(candidate)
|
1832
1862
|
else
|
1833
1863
|
candidate
|
1834
1864
|
end
|
@@ -1882,7 +1912,7 @@ module ActionDispatch
|
|
1882
1912
|
options_constraints = options.delete(:constraints) || {}
|
1883
1913
|
|
1884
1914
|
path_types = paths.group_by(&:class)
|
1885
|
-
path_types
|
1915
|
+
(path_types[String] || []).each do |_path|
|
1886
1916
|
route_options = options.dup
|
1887
1917
|
if _path && option_path
|
1888
1918
|
raise ArgumentError, "Ambiguous route definition. Both :path and the route path were specified as strings."
|
@@ -1891,7 +1921,7 @@ module ActionDispatch
|
|
1891
1921
|
decomposed_match(_path, controller, route_options, _path, to, via, formatted, anchor, options_constraints)
|
1892
1922
|
end
|
1893
1923
|
|
1894
|
-
path_types
|
1924
|
+
(path_types[Symbol] || []).each do |action|
|
1895
1925
|
route_options = options.dup
|
1896
1926
|
decomposed_match(action, controller, route_options, option_path, to, via, formatted, anchor, options_constraints)
|
1897
1927
|
end
|
@@ -1904,14 +1934,14 @@ module ActionDispatch
|
|
1904
1934
|
|
1905
1935
|
path_without_format = path.sub(/\(\.:format\)$/, "")
|
1906
1936
|
if using_match_shorthand?(path_without_format)
|
1907
|
-
path_without_format.
|
1937
|
+
path_without_format.delete_prefix("/").sub(%r{/([^/]*)$}, '#\1').tr("-", "_")
|
1908
1938
|
else
|
1909
1939
|
nil
|
1910
1940
|
end
|
1911
1941
|
end
|
1912
1942
|
|
1913
1943
|
def using_match_shorthand?(path)
|
1914
|
-
|
1944
|
+
%r{^/?[-\w]+/[-\w/]+$}.match?(path)
|
1915
1945
|
end
|
1916
1946
|
|
1917
1947
|
def decomposed_match(path, controller, options, _path, to, via, formatted, anchor, options_constraints)
|
@@ -1949,7 +1979,7 @@ module ActionDispatch
|
|
1949
1979
|
name_for_action(options.delete(:as), action)
|
1950
1980
|
end
|
1951
1981
|
|
1952
|
-
path = Mapping.normalize_path URI.
|
1982
|
+
path = Mapping.normalize_path URI::DEFAULT_PARSER.escape(path), formatted
|
1953
1983
|
ast = Journey::Parser.parse path
|
1954
1984
|
|
1955
1985
|
mapping = Mapping.build(@scope, @set, ast, controller, default_action, to, via, formatted, options_constraints, anchor, options)
|
@@ -2272,6 +2302,7 @@ module ActionDispatch
|
|
2272
2302
|
|
2273
2303
|
def initialize(set) #:nodoc:
|
2274
2304
|
@set = set
|
2305
|
+
@draw_paths = set.draw_paths
|
2275
2306
|
@scope = Scope.new(path_names: @set.resources_path_names)
|
2276
2307
|
@concerns = {}
|
2277
2308
|
end
|
@@ -145,6 +145,7 @@ module ActionDispatch
|
|
145
145
|
|
146
146
|
%w(edit new).each do |action|
|
147
147
|
module_eval <<-EOT, __FILE__, __LINE__ + 1
|
148
|
+
# frozen_string_literal: true
|
148
149
|
def #{action}_polymorphic_url(record_or_hash, options = {})
|
149
150
|
polymorphic_url_for_action("#{action}", record_or_hash, options)
|
150
151
|
end
|
@@ -173,15 +174,15 @@ module ActionDispatch
|
|
173
174
|
end
|
174
175
|
|
175
176
|
class HelperMethodBuilder # :nodoc:
|
176
|
-
CACHE = {
|
177
|
+
CACHE = { path: {}, url: {} }
|
177
178
|
|
178
179
|
def self.get(action, type)
|
179
|
-
type = type.
|
180
|
+
type = type.to_sym
|
180
181
|
CACHE[type].fetch(action) { build action, type }
|
181
182
|
end
|
182
183
|
|
183
|
-
def self.url; CACHE[
|
184
|
-
def self.path; CACHE[
|
184
|
+
def self.url; CACHE[:url][nil]; end
|
185
|
+
def self.path; CACHE[:path][nil]; end
|
185
186
|
|
186
187
|
def self.build(action, type)
|
187
188
|
prefix = action ? "#{action}_" : ""
|
@@ -227,9 +228,9 @@ module ActionDispatch
|
|
227
228
|
end
|
228
229
|
|
229
230
|
if options.empty?
|
230
|
-
recipient.
|
231
|
+
recipient.public_send(method, *args)
|
231
232
|
else
|
232
|
-
recipient.
|
233
|
+
recipient.public_send(method, *args, options)
|
233
234
|
end
|
234
235
|
end
|
235
236
|
|
@@ -246,7 +247,7 @@ module ActionDispatch
|
|
246
247
|
end
|
247
248
|
|
248
249
|
def handle_string_call(target, str)
|
249
|
-
target.
|
250
|
+
target.public_send get_method_for_string str
|
250
251
|
end
|
251
252
|
|
252
253
|
def handle_class(klass)
|
@@ -254,7 +255,7 @@ module ActionDispatch
|
|
254
255
|
end
|
255
256
|
|
256
257
|
def handle_class_call(target, klass)
|
257
|
-
target.
|
258
|
+
target.public_send get_method_for_class klass
|
258
259
|
end
|
259
260
|
|
260
261
|
def handle_model(record)
|
@@ -276,7 +277,7 @@ module ActionDispatch
|
|
276
277
|
mapping.call(target, [record], suffix == "path")
|
277
278
|
else
|
278
279
|
method, args = handle_model(record)
|
279
|
-
target.
|
280
|
+
target.public_send(method, *args)
|
280
281
|
end
|
281
282
|
end
|
282
283
|
|
@@ -286,12 +287,10 @@ module ActionDispatch
|
|
286
287
|
|
287
288
|
args = []
|
288
289
|
|
289
|
-
route = record_list.map
|
290
|
+
route = record_list.map { |parent|
|
290
291
|
case parent
|
291
|
-
when Symbol
|
292
|
+
when Symbol, String
|
292
293
|
parent.to_s
|
293
|
-
when String
|
294
|
-
raise(ArgumentError, "Please use symbols for polymorphic route arguments.")
|
295
294
|
when Class
|
296
295
|
args << parent
|
297
296
|
parent.model_name.singular_route_key
|
@@ -299,14 +298,12 @@ module ActionDispatch
|
|
299
298
|
args << parent.to_model
|
300
299
|
parent.to_model.model_name.singular_route_key
|
301
300
|
end
|
302
|
-
|
301
|
+
}
|
303
302
|
|
304
303
|
route <<
|
305
304
|
case record
|
306
|
-
when Symbol
|
305
|
+
when Symbol, String
|
307
306
|
record.to_s
|
308
|
-
when String
|
309
|
-
raise(ArgumentError, "Please use symbols for polymorphic route arguments.")
|
310
307
|
when Class
|
311
308
|
@key_strategy.call record.model_name
|
312
309
|
else
|
@@ -344,8 +341,8 @@ module ActionDispatch
|
|
344
341
|
end
|
345
342
|
|
346
343
|
[nil, "new", "edit"].each do |action|
|
347
|
-
CACHE[
|
348
|
-
CACHE[
|
344
|
+
CACHE[:url][action] = build action, "url"
|
345
|
+
CACHE[:path][action] = build action, "path"
|
349
346
|
end
|
350
347
|
end
|
351
348
|
end
|
@@ -65,15 +65,15 @@ module ActionDispatch
|
|
65
65
|
end
|
66
66
|
|
67
67
|
def escape(params)
|
68
|
-
|
68
|
+
params.transform_values { |v| Rack::Utils.escape(v) }
|
69
69
|
end
|
70
70
|
|
71
71
|
def escape_fragment(params)
|
72
|
-
|
72
|
+
params.transform_values { |v| Journey::Router::Utils.escape_fragment(v) }
|
73
73
|
end
|
74
74
|
|
75
75
|
def escape_path(params)
|
76
|
-
|
76
|
+
params.transform_values { |v| Journey::Router::Utils.escape_path(v) }
|
77
77
|
end
|
78
78
|
end
|
79
79
|
|