actionpack 6.1.7 → 7.0.4.1
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 +269 -406
- data/MIT-LICENSE +1 -0
- data/README.rdoc +2 -3
- data/lib/abstract_controller/asset_paths.rb +1 -1
- data/lib/abstract_controller/base.rb +13 -26
- data/lib/abstract_controller/caching/fragments.rb +2 -2
- data/lib/abstract_controller/caching.rb +1 -1
- data/lib/abstract_controller/callbacks.rb +21 -7
- data/lib/abstract_controller/collector.rb +2 -2
- data/lib/abstract_controller/error.rb +1 -1
- data/lib/abstract_controller/helpers.rb +4 -3
- data/lib/abstract_controller/logger.rb +1 -1
- data/lib/abstract_controller/railties/routes_helpers.rb +2 -0
- data/lib/abstract_controller/translation.rb +3 -2
- data/lib/abstract_controller/url_for.rb +4 -6
- data/lib/action_controller/api.rb +6 -6
- data/lib/action_controller/base.rb +5 -4
- data/lib/action_controller/form_builder.rb +2 -2
- data/lib/action_controller/log_subscriber.rb +4 -3
- data/lib/action_controller/metal/conditional_get.rb +39 -2
- data/lib/action_controller/metal/content_security_policy.rb +36 -2
- data/lib/action_controller/metal/cookies.rb +1 -1
- data/lib/action_controller/metal/data_streaming.rb +5 -13
- data/lib/action_controller/metal/exceptions.rb +19 -30
- data/lib/action_controller/metal/flash.rb +6 -2
- data/lib/action_controller/metal/helpers.rb +2 -2
- data/lib/action_controller/metal/http_authentication.rb +66 -39
- data/lib/action_controller/metal/instrumentation.rb +57 -52
- data/lib/action_controller/metal/live.rb +43 -2
- data/lib/action_controller/metal/mime_responds.rb +3 -3
- data/lib/action_controller/metal/params_wrapper.rb +20 -11
- data/lib/action_controller/metal/permissions_policy.rb +19 -28
- data/lib/action_controller/metal/redirecting.rb +93 -18
- data/lib/action_controller/metal/renderers.rb +10 -11
- data/lib/action_controller/metal/rendering.rb +8 -8
- data/lib/action_controller/metal/request_forgery_protection.rb +78 -29
- data/lib/action_controller/metal/rescue.rb +1 -1
- data/lib/action_controller/metal/streaming.rb +6 -8
- data/lib/action_controller/metal/strong_parameters.rb +100 -54
- data/lib/action_controller/metal/testing.rb +9 -2
- data/lib/action_controller/metal/url_for.rb +3 -3
- data/lib/action_controller/metal.rb +10 -13
- data/lib/action_controller/railtie.rb +49 -6
- data/lib/action_controller/renderer.rb +1 -1
- data/lib/action_controller/test_case.rb +28 -7
- data/lib/action_controller.rb +2 -5
- data/lib/action_dispatch/http/cache.rb +14 -7
- data/lib/action_dispatch/http/content_security_policy.rb +108 -35
- data/lib/action_dispatch/http/filter_parameters.rb +5 -0
- data/lib/action_dispatch/http/mime_negotiation.rb +15 -5
- data/lib/action_dispatch/http/mime_type.rb +9 -11
- data/lib/action_dispatch/http/parameters.rb +5 -5
- data/lib/action_dispatch/http/permissions_policy.rb +17 -1
- data/lib/action_dispatch/http/request.rb +12 -21
- data/lib/action_dispatch/http/response.rb +3 -16
- data/lib/action_dispatch/http/url.rb +11 -19
- data/lib/action_dispatch/journey/gtg/builder.rb +11 -12
- data/lib/action_dispatch/journey/gtg/simulator.rb +10 -4
- data/lib/action_dispatch/journey/gtg/transition_table.rb +77 -21
- data/lib/action_dispatch/journey/nodes/node.rb +70 -5
- data/lib/action_dispatch/journey/path/pattern.rb +22 -13
- data/lib/action_dispatch/journey/route.rb +6 -13
- data/lib/action_dispatch/journey/router/utils.rb +2 -2
- data/lib/action_dispatch/journey/router.rb +1 -1
- data/lib/action_dispatch/journey/routes.rb +3 -3
- data/lib/action_dispatch/journey/visualizer/fsm.js +49 -24
- data/lib/action_dispatch/journey/visualizer/index.html.erb +1 -1
- data/lib/action_dispatch/middleware/actionable_exceptions.rb +0 -1
- data/lib/action_dispatch/middleware/cookies.rb +42 -27
- data/lib/action_dispatch/middleware/debug_exceptions.rb +6 -4
- data/lib/action_dispatch/middleware/debug_locks.rb +3 -3
- data/lib/action_dispatch/middleware/exception_wrapper.rb +4 -0
- data/lib/action_dispatch/middleware/executor.rb +3 -0
- data/lib/action_dispatch/middleware/flash.rb +17 -18
- data/lib/action_dispatch/middleware/host_authorization.rb +1 -12
- data/lib/action_dispatch/middleware/remote_ip.rb +16 -4
- data/lib/action_dispatch/middleware/request_id.rb +1 -1
- data/lib/action_dispatch/middleware/server_timing.rb +76 -0
- data/lib/action_dispatch/middleware/session/abstract_store.rb +1 -1
- data/lib/action_dispatch/middleware/session/cookie_store.rb +9 -9
- data/lib/action_dispatch/middleware/show_exceptions.rb +7 -9
- data/lib/action_dispatch/middleware/stack.rb +27 -9
- data/lib/action_dispatch/middleware/static.rb +2 -6
- data/lib/action_dispatch/middleware/templates/rescues/_message_and_suggestions.html.erb +1 -1
- data/lib/action_dispatch/middleware/templates/rescues/_request_and_response.html.erb +4 -11
- data/lib/action_dispatch/middleware/templates/rescues/_trace.html.erb +2 -2
- data/lib/action_dispatch/middleware/templates/rescues/blocked_host.html.erb +3 -2
- data/lib/action_dispatch/middleware/templates/rescues/blocked_host.text.erb +2 -0
- data/lib/action_dispatch/middleware/templates/rescues/diagnostics.html.erb +4 -4
- data/lib/action_dispatch/middleware/templates/rescues/invalid_statement.html.erb +3 -3
- data/lib/action_dispatch/middleware/templates/rescues/layout.erb +28 -18
- data/lib/action_dispatch/middleware/templates/rescues/missing_exact_template.html.erb +3 -3
- data/lib/action_dispatch/middleware/templates/rescues/missing_template.html.erb +3 -3
- data/lib/action_dispatch/middleware/templates/rescues/routing_error.html.erb +3 -3
- data/lib/action_dispatch/middleware/templates/rescues/template_error.html.erb +3 -3
- data/lib/action_dispatch/middleware/templates/rescues/unknown_action.html.erb +3 -3
- data/lib/action_dispatch/middleware/templates/routes/_table.html.erb +5 -14
- data/lib/action_dispatch/railtie.rb +8 -2
- data/lib/action_dispatch/request/session.rb +43 -13
- data/lib/action_dispatch/routing/inspector.rb +1 -1
- data/lib/action_dispatch/routing/mapper.rb +59 -83
- data/lib/action_dispatch/routing/redirection.rb +5 -2
- data/lib/action_dispatch/routing/route_set.rb +17 -7
- data/lib/action_dispatch/routing/routes_proxy.rb +1 -1
- data/lib/action_dispatch/routing/url_for.rb +4 -5
- data/lib/action_dispatch/routing.rb +5 -6
- data/lib/action_dispatch/system_test_case.rb +5 -5
- data/lib/action_dispatch/system_testing/browser.rb +2 -12
- data/lib/action_dispatch/system_testing/driver.rb +35 -11
- data/lib/action_dispatch/system_testing/test_helpers/screenshot_helper.rb +11 -7
- data/lib/action_dispatch/system_testing/test_helpers/setup_and_teardown.rb +0 -8
- data/lib/action_dispatch/testing/assertions/routing.rb +3 -2
- data/lib/action_dispatch/testing/assertions.rb +2 -5
- data/lib/action_dispatch/testing/integration.rb +6 -8
- data/lib/action_dispatch/testing/test_process.rb +3 -29
- data/lib/action_dispatch/testing/test_response.rb +20 -2
- data/lib/action_dispatch.rb +1 -0
- data/lib/action_pack/gem_version.rb +5 -5
- data/lib/action_pack/version.rb +1 -1
- metadata +16 -15
@@ -4,7 +4,6 @@ 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"
|
8
7
|
require "action_dispatch/routing/redirection"
|
9
8
|
require "action_dispatch/routing/endpoint"
|
10
9
|
|
@@ -13,7 +12,7 @@ module ActionDispatch
|
|
13
12
|
class Mapper
|
14
13
|
URL_OPTIONS = [:protocol, :subdomain, :domain, :host, :port]
|
15
14
|
|
16
|
-
class Constraints < Routing::Endpoint
|
15
|
+
class Constraints < Routing::Endpoint # :nodoc:
|
17
16
|
attr_reader :app, :constraints
|
18
17
|
|
19
18
|
SERVE = ->(app, req) { app.serve req }
|
@@ -67,11 +66,11 @@ module ActionDispatch
|
|
67
66
|
end
|
68
67
|
end
|
69
68
|
|
70
|
-
class Mapping
|
69
|
+
class Mapping # :nodoc:
|
71
70
|
ANCHOR_CHARACTERS_REGEX = %r{\A(\\A|\^)|(\\Z|\\z|\$)\Z}
|
72
71
|
OPTIONAL_FORMAT_REGEX = %r{(?:\(\.:format\)+|\.:format|/)\Z}
|
73
72
|
|
74
|
-
attr_reader :requirements, :defaults, :to, :default_controller,
|
73
|
+
attr_reader :path, :requirements, :defaults, :to, :default_controller,
|
75
74
|
:default_action, :required_defaults, :ast, :scope_options
|
76
75
|
|
77
76
|
def self.build(scope, set, ast, controller, default_action, to, via, formatted, options_constraints, anchor, options)
|
@@ -122,31 +121,17 @@ module ActionDispatch
|
|
122
121
|
@to = intern(to)
|
123
122
|
@default_controller = intern(controller)
|
124
123
|
@default_action = intern(default_action)
|
125
|
-
@ast = ast
|
126
124
|
@anchor = anchor
|
127
125
|
@via = via
|
128
126
|
@internal = options.delete(:internal)
|
129
127
|
@scope_options = scope_params[:options]
|
128
|
+
ast = Journey::Ast.new(ast, formatted)
|
130
129
|
|
131
|
-
|
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
|
144
|
-
|
145
|
-
options = wildcard_options.merge!(options)
|
130
|
+
options = ast.wildcard_options.merge!(options)
|
146
131
|
|
147
|
-
options = normalize_options!(options, path_params, scope_params[:module])
|
132
|
+
options = normalize_options!(options, ast.path_params, scope_params[:module])
|
148
133
|
|
149
|
-
split_options = constraints(options, path_params)
|
134
|
+
split_options = constraints(options, ast.path_params)
|
150
135
|
|
151
136
|
constraints = scope_params[:constraints].merge Hash[split_options[:constraints] || []]
|
152
137
|
|
@@ -160,8 +145,8 @@ module ActionDispatch
|
|
160
145
|
@blocks = blocks(options_constraints)
|
161
146
|
end
|
162
147
|
|
163
|
-
requirements, conditions = split_constraints path_params, constraints
|
164
|
-
verify_regexp_requirements requirements.
|
148
|
+
requirements, conditions = split_constraints ast.path_params, constraints
|
149
|
+
verify_regexp_requirements requirements, ast.wildcard_options
|
165
150
|
|
166
151
|
formats = normalize_format(formatted)
|
167
152
|
|
@@ -169,13 +154,18 @@ module ActionDispatch
|
|
169
154
|
@conditions = Hash[conditions]
|
170
155
|
@defaults = formats[:defaults].merge(@defaults).merge(normalize_defaults(options))
|
171
156
|
|
172
|
-
if path_params.include?(:action) && !@requirements.key?(:action)
|
157
|
+
if ast.path_params.include?(:action) && !@requirements.key?(:action)
|
173
158
|
@defaults[:action] ||= "index"
|
174
159
|
end
|
175
160
|
|
176
161
|
@required_defaults = (split_options[:required_defaults] || []).map(&:first)
|
162
|
+
|
163
|
+
ast.requirements = @requirements
|
164
|
+
@path = Journey::Path::Pattern.new(ast, @requirements, JOINED_SEPARATORS, @anchor)
|
177
165
|
end
|
178
166
|
|
167
|
+
JOINED_SEPARATORS = SEPARATORS.join # :nodoc:
|
168
|
+
|
179
169
|
def make_route(name, precedence)
|
180
170
|
Journey::Route.new(name: name, app: application, path: path, constraints: conditions,
|
181
171
|
required_defaults: required_defaults, defaults: defaults,
|
@@ -187,12 +177,6 @@ module ActionDispatch
|
|
187
177
|
app(@blocks)
|
188
178
|
end
|
189
179
|
|
190
|
-
JOINED_SEPARATORS = SEPARATORS.join # :nodoc:
|
191
|
-
|
192
|
-
def path
|
193
|
-
Journey::Path::Pattern.new(@ast, requirements, JOINED_SEPARATORS, @anchor)
|
194
|
-
end
|
195
|
-
|
196
180
|
def conditions
|
197
181
|
build_conditions @conditions, @set.request_class
|
198
182
|
end
|
@@ -212,24 +196,6 @@ module ActionDispatch
|
|
212
196
|
private :request_method
|
213
197
|
|
214
198
|
private
|
215
|
-
# Find all the symbol nodes that are adjacent to literal nodes and alter
|
216
|
-
# the regexp so that Journey will partition them into custom routes.
|
217
|
-
def alter_regex_for_custom_routes(node)
|
218
|
-
if node.left.literal? && node.right.symbol?
|
219
|
-
symbol = node.right
|
220
|
-
elsif node.left.literal? && node.right.cat? && node.right.left.symbol?
|
221
|
-
symbol = node.right.left
|
222
|
-
elsif node.left.symbol? && node.right.literal?
|
223
|
-
symbol = node.left
|
224
|
-
elsif node.left.symbol? && node.right.cat? && node.right.left.literal?
|
225
|
-
symbol = node.left
|
226
|
-
end
|
227
|
-
|
228
|
-
if symbol
|
229
|
-
symbol.regexp = /(?:#{Regexp.union(symbol.regexp, '-')})+/
|
230
|
-
end
|
231
|
-
end
|
232
|
-
|
233
199
|
def intern(object)
|
234
200
|
object.is_a?(String) ? -object : object
|
235
201
|
end
|
@@ -280,14 +246,18 @@ module ActionDispatch
|
|
280
246
|
end
|
281
247
|
end
|
282
248
|
|
283
|
-
def verify_regexp_requirements(requirements)
|
284
|
-
requirements.each do |requirement|
|
285
|
-
|
249
|
+
def verify_regexp_requirements(requirements, wildcard_options)
|
250
|
+
requirements.each do |requirement, regex|
|
251
|
+
next unless regex.is_a? Regexp
|
252
|
+
|
253
|
+
if ANCHOR_CHARACTERS_REGEX.match?(regex.source)
|
286
254
|
raise ArgumentError, "Regexp anchor characters are not allowed in routing requirements: #{requirement.inspect}"
|
287
255
|
end
|
288
256
|
|
289
|
-
if
|
290
|
-
|
257
|
+
if regex.multiline?
|
258
|
+
next if wildcard_options.key?(requirement)
|
259
|
+
|
260
|
+
raise ArgumentError, "Regexp multiline option is not allowed in routing requirements: #{regex.inspect}"
|
291
261
|
end
|
292
262
|
end
|
293
263
|
end
|
@@ -420,10 +390,10 @@ module ActionDispatch
|
|
420
390
|
#
|
421
391
|
# If you want to expose your action to both GET and POST, use:
|
422
392
|
#
|
423
|
-
# # sets :controller, :action and :id in params
|
393
|
+
# # sets :controller, :action, and :id in params
|
424
394
|
# match ':controller/:action/:id', via: [:get, :post]
|
425
395
|
#
|
426
|
-
# Note that +:controller+, +:action
|
396
|
+
# Note that +:controller+, +:action+, and +:id+ are interpreted as URL
|
427
397
|
# query parameters and thus available through +params+ in an action.
|
428
398
|
#
|
429
399
|
# If you want to expose your action to GET, use +get+ in the router:
|
@@ -639,7 +609,7 @@ module ActionDispatch
|
|
639
609
|
target_as = name_for_action(options[:as], path)
|
640
610
|
options[:via] ||= :all
|
641
611
|
|
642
|
-
match(path,
|
612
|
+
match(path, { to: app, anchor: false, format: false }.merge(options))
|
643
613
|
|
644
614
|
define_generate_prefix(app, target_as) if rails_app
|
645
615
|
self
|
@@ -936,7 +906,7 @@ module ActionDispatch
|
|
936
906
|
#
|
937
907
|
# === Options
|
938
908
|
#
|
939
|
-
# The +:path+, +:as+, +:module+, +:shallow_path
|
909
|
+
# The +:path+, +:as+, +:module+, +:shallow_path+, and +:shallow_prefix+
|
940
910
|
# options all default to the name of the namespace.
|
941
911
|
#
|
942
912
|
# For options, see <tt>Base#match</tt>. For +:shallow_path+ option, see
|
@@ -956,7 +926,7 @@ module ActionDispatch
|
|
956
926
|
# namespace :admin, as: "sekret" do
|
957
927
|
# resources :posts
|
958
928
|
# end
|
959
|
-
def namespace(path, options = {})
|
929
|
+
def namespace(path, options = {}, &block)
|
960
930
|
path = path.to_s
|
961
931
|
|
962
932
|
defaults = {
|
@@ -967,7 +937,7 @@ module ActionDispatch
|
|
967
937
|
}
|
968
938
|
|
969
939
|
path_scope(options.delete(:path) { path }) do
|
970
|
-
scope(defaults.merge!(options))
|
940
|
+
scope(defaults.merge!(options), &block)
|
971
941
|
end
|
972
942
|
end
|
973
943
|
|
@@ -1026,8 +996,8 @@ module ActionDispatch
|
|
1026
996
|
# constraints(Iphone) do
|
1027
997
|
# resources :iphones
|
1028
998
|
# end
|
1029
|
-
def constraints(constraints = {})
|
1030
|
-
scope(constraints: constraints)
|
999
|
+
def constraints(constraints = {}, &block)
|
1000
|
+
scope(constraints: constraints, &block)
|
1031
1001
|
end
|
1032
1002
|
|
1033
1003
|
# Allows you to set default parameters for a route, such as this:
|
@@ -1112,7 +1082,7 @@ module ActionDispatch
|
|
1112
1082
|
|
1113
1083
|
# Resource routing allows you to quickly declare all of the common routes
|
1114
1084
|
# for a given resourceful controller. Instead of declaring separate routes
|
1115
|
-
# for your +index+, +show+, +new+, +edit+, +create+, +update
|
1085
|
+
# for your +index+, +show+, +new+, +edit+, +create+, +update+, and +destroy+
|
1116
1086
|
# actions, a resourceful route declares them in a single line of code:
|
1117
1087
|
#
|
1118
1088
|
# resources :photos
|
@@ -1156,7 +1126,7 @@ module ActionDispatch
|
|
1156
1126
|
RESOURCE_OPTIONS = [:as, :controller, :path, :only, :except, :param, :concerns]
|
1157
1127
|
CANONICAL_ACTIONS = %w(index create new show update destroy)
|
1158
1128
|
|
1159
|
-
class Resource
|
1129
|
+
class Resource # :nodoc:
|
1160
1130
|
attr_reader :controller, :path, :param
|
1161
1131
|
|
1162
1132
|
def initialize(entities, api_only, shallow, options = {})
|
@@ -1251,7 +1221,7 @@ module ActionDispatch
|
|
1251
1221
|
def singleton?; false; end
|
1252
1222
|
end
|
1253
1223
|
|
1254
|
-
class SingletonResource < Resource
|
1224
|
+
class SingletonResource < Resource # :nodoc:
|
1255
1225
|
def initialize(entities, api_only, shallow, options)
|
1256
1226
|
super
|
1257
1227
|
@as = nil
|
@@ -1307,6 +1277,16 @@ module ActionDispatch
|
|
1307
1277
|
# DELETE /profile
|
1308
1278
|
# POST /profile
|
1309
1279
|
#
|
1280
|
+
# If you want instances of a model to work with this resource via
|
1281
|
+
# record identification (e.g. in +form_with+ or +redirect_to+), you
|
1282
|
+
# will need to call resolve[rdoc-ref:CustomUrls#resolve]:
|
1283
|
+
#
|
1284
|
+
# resource :profile
|
1285
|
+
# resolve('Profile') { [:profile] }
|
1286
|
+
#
|
1287
|
+
# # Enables this to work with singular routes:
|
1288
|
+
# form_with(model: @profile) {}
|
1289
|
+
#
|
1310
1290
|
# === Options
|
1311
1291
|
# Takes same options as resources[rdoc-ref:#resources]
|
1312
1292
|
def resource(*resources, &block)
|
@@ -1517,15 +1497,13 @@ module ActionDispatch
|
|
1517
1497
|
# with GET, and route to the search action of +PhotosController+. It will also
|
1518
1498
|
# create the <tt>search_photos_url</tt> and <tt>search_photos_path</tt>
|
1519
1499
|
# route helpers.
|
1520
|
-
def collection
|
1500
|
+
def collection(&block)
|
1521
1501
|
unless resource_scope?
|
1522
1502
|
raise ArgumentError, "can't use collection outside resource(s) scope"
|
1523
1503
|
end
|
1524
1504
|
|
1525
1505
|
with_scope_level(:collection) do
|
1526
|
-
path_scope(parent_resource.collection_scope)
|
1527
|
-
yield
|
1528
|
-
end
|
1506
|
+
path_scope(parent_resource.collection_scope, &block)
|
1529
1507
|
end
|
1530
1508
|
end
|
1531
1509
|
|
@@ -1540,7 +1518,7 @@ module ActionDispatch
|
|
1540
1518
|
# This will recognize <tt>/photos/1/preview</tt> with GET, and route to the
|
1541
1519
|
# preview action of +PhotosController+. It will also create the
|
1542
1520
|
# <tt>preview_photo_url</tt> and <tt>preview_photo_path</tt> helpers.
|
1543
|
-
def member
|
1521
|
+
def member(&block)
|
1544
1522
|
unless resource_scope?
|
1545
1523
|
raise ArgumentError, "can't use member outside resource(s) scope"
|
1546
1524
|
end
|
@@ -1548,27 +1526,25 @@ module ActionDispatch
|
|
1548
1526
|
with_scope_level(:member) do
|
1549
1527
|
if shallow?
|
1550
1528
|
shallow_scope {
|
1551
|
-
path_scope(parent_resource.member_scope)
|
1529
|
+
path_scope(parent_resource.member_scope, &block)
|
1552
1530
|
}
|
1553
1531
|
else
|
1554
|
-
path_scope(parent_resource.member_scope)
|
1532
|
+
path_scope(parent_resource.member_scope, &block)
|
1555
1533
|
end
|
1556
1534
|
end
|
1557
1535
|
end
|
1558
1536
|
|
1559
|
-
def new
|
1537
|
+
def new(&block)
|
1560
1538
|
unless resource_scope?
|
1561
1539
|
raise ArgumentError, "can't use new outside resource(s) scope"
|
1562
1540
|
end
|
1563
1541
|
|
1564
1542
|
with_scope_level(:new) do
|
1565
|
-
path_scope(parent_resource.new_scope(action_path(:new)))
|
1566
|
-
yield
|
1567
|
-
end
|
1543
|
+
path_scope(parent_resource.new_scope(action_path(:new)), &block)
|
1568
1544
|
end
|
1569
1545
|
end
|
1570
1546
|
|
1571
|
-
def nested
|
1547
|
+
def nested(&block)
|
1572
1548
|
unless resource_scope?
|
1573
1549
|
raise ArgumentError, "can't use nested outside resource(s) scope"
|
1574
1550
|
end
|
@@ -1577,12 +1553,12 @@ module ActionDispatch
|
|
1577
1553
|
if shallow? && shallow_nesting_depth >= 1
|
1578
1554
|
shallow_scope do
|
1579
1555
|
path_scope(parent_resource.nested_scope) do
|
1580
|
-
scope(nested_options)
|
1556
|
+
scope(nested_options, &block)
|
1581
1557
|
end
|
1582
1558
|
end
|
1583
1559
|
else
|
1584
1560
|
path_scope(parent_resource.nested_scope) do
|
1585
|
-
scope(nested_options)
|
1561
|
+
scope(nested_options, &block)
|
1586
1562
|
end
|
1587
1563
|
end
|
1588
1564
|
end
|
@@ -1768,10 +1744,10 @@ module ActionDispatch
|
|
1768
1744
|
@scope = @scope.parent
|
1769
1745
|
end
|
1770
1746
|
|
1771
|
-
def resource_scope(resource)
|
1747
|
+
def resource_scope(resource, &block)
|
1772
1748
|
@scope = @scope.new(scope_level_resource: resource)
|
1773
1749
|
|
1774
|
-
controller(resource.resource_scope)
|
1750
|
+
controller(resource.resource_scope, &block)
|
1775
1751
|
ensure
|
1776
1752
|
@scope = @scope.parent
|
1777
1753
|
end
|
@@ -1889,7 +1865,7 @@ module ActionDispatch
|
|
1889
1865
|
end
|
1890
1866
|
|
1891
1867
|
def map_match(paths, options)
|
1892
|
-
if options[:on] && !VALID_ON_OPTIONS.include?(
|
1868
|
+
if (on = options[:on]) && !VALID_ON_OPTIONS.include?(on)
|
1893
1869
|
raise ArgumentError, "Unknown scope #{on.inspect} given to :on"
|
1894
1870
|
end
|
1895
1871
|
|
@@ -2300,7 +2276,7 @@ module ActionDispatch
|
|
2300
2276
|
NULL = Scope.new(nil, nil)
|
2301
2277
|
end
|
2302
2278
|
|
2303
|
-
def initialize(set)
|
2279
|
+
def initialize(set) # :nodoc:
|
2304
2280
|
@set = set
|
2305
2281
|
@draw_paths = set.draw_paths
|
2306
2282
|
@scope = Scope.new(path_names: @set.resources_path_names)
|
@@ -1,7 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require "action_dispatch/http/request"
|
4
|
-
require "active_support/core_ext/uri"
|
5
3
|
require "active_support/core_ext/array/extract_options"
|
6
4
|
require "rack/utils"
|
7
5
|
require "action_controller/metal/exceptions"
|
@@ -144,6 +142,11 @@ module ActionDispatch
|
|
144
142
|
# This will redirect the user, while ignoring certain parts of the request, including query string, etc.
|
145
143
|
# <tt>/stories</tt>, <tt>/stories?foo=bar</tt>, etc all redirect to <tt>/posts</tt>.
|
146
144
|
#
|
145
|
+
# The redirect will use a <tt>301 Moved Permanently</tt> status code by
|
146
|
+
# default. This can be overridden with the +:status+ option:
|
147
|
+
#
|
148
|
+
# get "/stories" => redirect("/posts", status: 307)
|
149
|
+
#
|
147
150
|
# You can also use interpolation in the supplied redirect argument:
|
148
151
|
#
|
149
152
|
# get 'docs/:article', to: redirect('/wiki/%{article}')
|
@@ -6,7 +6,6 @@ require "active_support/core_ext/module/redefine_method"
|
|
6
6
|
require "active_support/core_ext/module/remove_method"
|
7
7
|
require "active_support/core_ext/array/extract_options"
|
8
8
|
require "action_controller/metal/exceptions"
|
9
|
-
require "action_dispatch/http/request"
|
10
9
|
require "action_dispatch/routing/endpoint"
|
11
10
|
|
12
11
|
module ActionDispatch
|
@@ -132,8 +131,8 @@ module ActionDispatch
|
|
132
131
|
alias [] get
|
133
132
|
alias clear clear!
|
134
133
|
|
135
|
-
def each
|
136
|
-
routes.each
|
134
|
+
def each(&block)
|
135
|
+
routes.each(&block)
|
137
136
|
self
|
138
137
|
end
|
139
138
|
|
@@ -197,7 +196,9 @@ module ActionDispatch
|
|
197
196
|
def call(t, method_name, args, inner_options, url_strategy)
|
198
197
|
if args.size == arg_size && !inner_options && optimize_routes_generation?(t)
|
199
198
|
options = t.url_options.merge @options
|
200
|
-
|
199
|
+
path = optimized_helper(args)
|
200
|
+
path << "/" if options[:trailing_slash] && !path.end_with?("/")
|
201
|
+
options[:path] = path
|
201
202
|
|
202
203
|
original_script_name = options.delete(:original_script_name)
|
203
204
|
script_name = t._routes.find_script_name(options)
|
@@ -597,14 +598,14 @@ module ActionDispatch
|
|
597
598
|
if route.segment_keys.include?(:controller)
|
598
599
|
ActiveSupport::Deprecation.warn(<<-MSG.squish)
|
599
600
|
Using a dynamic :controller segment in a route is deprecated and
|
600
|
-
will be removed in Rails 7.
|
601
|
+
will be removed in Rails 7.1.
|
601
602
|
MSG
|
602
603
|
end
|
603
604
|
|
604
605
|
if route.segment_keys.include?(:action)
|
605
606
|
ActiveSupport::Deprecation.warn(<<-MSG.squish)
|
606
607
|
Using a dynamic :action segment in a route is deprecated and
|
607
|
-
will be removed in Rails 7.
|
608
|
+
will be removed in Rails 7.1.
|
608
609
|
MSG
|
609
610
|
end
|
610
611
|
|
@@ -821,10 +822,19 @@ module ActionDispatch
|
|
821
822
|
|
822
823
|
route_with_params = generate(route_name, path_options, recall)
|
823
824
|
path = route_with_params.path(method_name)
|
825
|
+
|
826
|
+
if options[:trailing_slash] && !options[:format] && !path.end_with?("/")
|
827
|
+
path += "/"
|
828
|
+
end
|
829
|
+
|
824
830
|
params = route_with_params.params
|
825
831
|
|
826
832
|
if options.key? :params
|
827
|
-
|
833
|
+
if options[:params]&.respond_to?(:to_hash)
|
834
|
+
params.merge! options[:params]
|
835
|
+
else
|
836
|
+
params[:params] = options[:params]
|
837
|
+
end
|
828
838
|
end
|
829
839
|
|
830
840
|
options[:path] = path
|
@@ -70,7 +70,7 @@ module ActionDispatch
|
|
70
70
|
# resources :users
|
71
71
|
#
|
72
72
|
# This generates, among other things, the method <tt>users_path</tt>. By default,
|
73
|
-
# this method is accessible from your controllers, views and mailers. If you need
|
73
|
+
# this method is accessible from your controllers, views, and mailers. If you need
|
74
74
|
# to access this auto-generated method from other places (such as a model), then
|
75
75
|
# you can do that by including Rails.application.routes.url_helpers in your class:
|
76
76
|
#
|
@@ -103,11 +103,10 @@ module ActionDispatch
|
|
103
103
|
include(*_url_for_modules) if respond_to?(:_url_for_modules)
|
104
104
|
end
|
105
105
|
|
106
|
-
def initialize(
|
106
|
+
def initialize(...)
|
107
107
|
@_routes = nil
|
108
108
|
super
|
109
109
|
end
|
110
|
-
ruby2_keywords(:initialize) if respond_to?(:ruby2_keywords, true)
|
111
110
|
|
112
111
|
# Hook overridden in controller to add request information
|
113
112
|
# with +default_url_options+. Application logic should not
|
@@ -116,7 +115,7 @@ module ActionDispatch
|
|
116
115
|
default_url_options
|
117
116
|
end
|
118
117
|
|
119
|
-
# Generate a URL based on the options provided, default_url_options and the
|
118
|
+
# Generate a URL based on the options provided, default_url_options, and the
|
120
119
|
# routes defined in routes.rb. The following options are supported:
|
121
120
|
#
|
122
121
|
# * <tt>:only_path</tt> - If true, the relative URL is returned. Defaults to +false+.
|
@@ -155,7 +154,7 @@ module ActionDispatch
|
|
155
154
|
# # => '/myapp/tasks/testing'
|
156
155
|
#
|
157
156
|
# Missing routes keys may be filled in from the current request's parameters
|
158
|
-
# (e.g. +:controller+, +:action+, +:id
|
157
|
+
# (e.g. +:controller+, +:action+, +:id+, and any other parameters that are
|
159
158
|
# placed in the path). Given that the current action has been reached
|
160
159
|
# through <tt>GET /users/1</tt>:
|
161
160
|
#
|
@@ -28,7 +28,7 @@ module ActionDispatch
|
|
28
28
|
#
|
29
29
|
# Resource routing allows you to quickly declare all of the common routes
|
30
30
|
# for a given resourceful controller. Instead of declaring separate routes
|
31
|
-
# for your +index+, +show+, +new+, +edit+, +create+, +update
|
31
|
+
# for your +index+, +show+, +new+, +edit+, +create+, +update+, and +destroy+
|
32
32
|
# actions, a resourceful route declares them in a single line of code:
|
33
33
|
#
|
34
34
|
# resources :photos
|
@@ -65,9 +65,8 @@ module ActionDispatch
|
|
65
65
|
# resources :posts, :comments
|
66
66
|
# end
|
67
67
|
#
|
68
|
-
# For more, see
|
69
|
-
#
|
70
|
-
# <tt>Routing::Mapper::Scoping#scope</tt>.
|
68
|
+
# For more, see Routing::Mapper::Resources#resources,
|
69
|
+
# Routing::Mapper::Scoping#namespace, and Routing::Mapper::Scoping#scope.
|
71
70
|
#
|
72
71
|
# == Non-resourceful routes
|
73
72
|
#
|
@@ -255,7 +254,7 @@ module ActionDispatch
|
|
255
254
|
autoload :UrlFor
|
256
255
|
autoload :PolymorphicRoutes
|
257
256
|
|
258
|
-
SEPARATORS = %w( / . ? )
|
259
|
-
HTTP_METHODS = [:get, :head, :post, :patch, :put, :delete, :options]
|
257
|
+
SEPARATORS = %w( / . ? ) # :nodoc:
|
258
|
+
HTTP_METHODS = [:get, :head, :post, :patch, :put, :delete, :options] # :nodoc:
|
260
259
|
end
|
261
260
|
end
|
@@ -72,8 +72,8 @@ module ActionDispatch
|
|
72
72
|
# Headless browsers such as headless Chrome and headless Firefox are also supported.
|
73
73
|
# You can use these browsers by setting the +:using+ argument to +:headless_chrome+ or +:headless_firefox+.
|
74
74
|
#
|
75
|
-
# To use a headless driver, like
|
76
|
-
#
|
75
|
+
# To use a headless driver, like Cuprite, update your Gemfile to use
|
76
|
+
# Cuprite instead of Selenium and then declare the driver name in the
|
77
77
|
# +application_system_test_case.rb+ file. In this case, you would leave out
|
78
78
|
# the +:using+ option because the driver is headless, but you can still use
|
79
79
|
# +:screen_size+ to change the size of the browser screen, also you can use
|
@@ -81,10 +81,10 @@ module ActionDispatch
|
|
81
81
|
# driver documentation to learn about supported options.
|
82
82
|
#
|
83
83
|
# require "test_helper"
|
84
|
-
# require "capybara/
|
84
|
+
# require "capybara/cuprite"
|
85
85
|
#
|
86
86
|
# class ApplicationSystemTestCase < ActionDispatch::SystemTestCase
|
87
|
-
# driven_by :
|
87
|
+
# driven_by :cuprite, screen_size: [1400, 1400], options:
|
88
88
|
# { js_errors: true }
|
89
89
|
# end
|
90
90
|
#
|
@@ -142,7 +142,7 @@ module ActionDispatch
|
|
142
142
|
#
|
143
143
|
# Examples:
|
144
144
|
#
|
145
|
-
# driven_by :
|
145
|
+
# driven_by :cuprite
|
146
146
|
#
|
147
147
|
# driven_by :selenium, screen_size: [800, 800]
|
148
148
|
#
|
@@ -33,19 +33,9 @@ module ActionDispatch
|
|
33
33
|
def preload
|
34
34
|
case type
|
35
35
|
when :chrome
|
36
|
-
|
37
|
-
::Selenium::WebDriver::Chrome::Service.driver_path&.call
|
38
|
-
else
|
39
|
-
# Selenium <= v3.141.0
|
40
|
-
::Selenium::WebDriver::Chrome.driver_path
|
41
|
-
end
|
36
|
+
::Selenium::WebDriver::Chrome::Service.driver_path&.call
|
42
37
|
when :firefox
|
43
|
-
|
44
|
-
::Selenium::WebDriver::Firefox::Service.driver_path&.call
|
45
|
-
else
|
46
|
-
# Selenium <= v3.141.0
|
47
|
-
::Selenium::WebDriver::Firefox.driver_path
|
48
|
-
end
|
38
|
+
::Selenium::WebDriver::Firefox::Service.driver_path&.call
|
49
39
|
end
|
50
40
|
end
|
51
41
|
|
@@ -3,16 +3,30 @@
|
|
3
3
|
module ActionDispatch
|
4
4
|
module SystemTesting
|
5
5
|
class Driver # :nodoc:
|
6
|
-
|
7
|
-
|
8
|
-
|
6
|
+
attr_reader :name
|
7
|
+
|
8
|
+
def initialize(driver_type, **options, &capabilities)
|
9
|
+
@driver_type = driver_type
|
9
10
|
@screen_size = options[:screen_size]
|
10
11
|
@options = options[:options] || {}
|
12
|
+
@name = @options.delete(:name) || driver_type
|
11
13
|
@capabilities = capabilities
|
12
14
|
|
13
|
-
if
|
15
|
+
if [:poltergeist, :webkit].include?(driver_type)
|
16
|
+
ActiveSupport::Deprecation.warn <<~MSG.squish
|
17
|
+
Poltergeist and capybara-webkit are not maintained already.
|
18
|
+
Driver registration of :poltergeist or :webkit is deprecated and will be removed in Rails 7.1.
|
19
|
+
You can still use :selenium, and also :cuprite is available for alternative to Poltergeist.
|
20
|
+
MSG
|
21
|
+
end
|
22
|
+
|
23
|
+
if driver_type == :selenium
|
24
|
+
gem "selenium-webdriver", ">= 4.0.0"
|
14
25
|
require "selenium/webdriver"
|
26
|
+
@browser = Browser.new(options[:using])
|
15
27
|
@browser.preload
|
28
|
+
else
|
29
|
+
@browser = nil
|
16
30
|
end
|
17
31
|
end
|
18
32
|
|
@@ -24,27 +38,29 @@ module ActionDispatch
|
|
24
38
|
|
25
39
|
private
|
26
40
|
def registerable?
|
27
|
-
[:selenium, :poltergeist, :webkit].include?(@
|
41
|
+
[:selenium, :poltergeist, :webkit, :cuprite, :rack_test].include?(@driver_type)
|
28
42
|
end
|
29
43
|
|
30
44
|
def register
|
31
|
-
@browser
|
45
|
+
@browser&.configure(&@capabilities)
|
32
46
|
|
33
|
-
Capybara.register_driver
|
34
|
-
case @
|
47
|
+
Capybara.register_driver name do |app|
|
48
|
+
case @driver_type
|
35
49
|
when :selenium then register_selenium(app)
|
36
50
|
when :poltergeist then register_poltergeist(app)
|
37
51
|
when :webkit then register_webkit(app)
|
52
|
+
when :cuprite then register_cuprite(app)
|
53
|
+
when :rack_test then register_rack_test(app)
|
38
54
|
end
|
39
55
|
end
|
40
56
|
end
|
41
57
|
|
42
58
|
def browser_options
|
43
|
-
@options.merge(
|
59
|
+
@options.merge(capabilities: @browser.options).compact
|
44
60
|
end
|
45
61
|
|
46
62
|
def register_selenium(app)
|
47
|
-
Capybara::Selenium::Driver.new(app,
|
63
|
+
Capybara::Selenium::Driver.new(app, browser: @browser.type, **browser_options).tap do |driver|
|
48
64
|
driver.browser.manage.window.size = Selenium::WebDriver::Dimension.new(*@screen_size)
|
49
65
|
end
|
50
66
|
end
|
@@ -59,8 +75,16 @@ module ActionDispatch
|
|
59
75
|
end
|
60
76
|
end
|
61
77
|
|
78
|
+
def register_cuprite(app)
|
79
|
+
Capybara::Cuprite::Driver.new(app, @options.merge(window_size: @screen_size))
|
80
|
+
end
|
81
|
+
|
82
|
+
def register_rack_test(app)
|
83
|
+
Capybara::RackTest::Driver.new(app, respect_data_method: true, **@options)
|
84
|
+
end
|
85
|
+
|
62
86
|
def setup
|
63
|
-
Capybara.current_driver =
|
87
|
+
Capybara.current_driver = name
|
64
88
|
end
|
65
89
|
end
|
66
90
|
end
|