actionpack 6.1.7.6 → 7.0.0.alpha1
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 +99 -584
- data/MIT-LICENSE +2 -1
- data/README.rdoc +2 -3
- data/lib/abstract_controller/asset_paths.rb +1 -1
- data/lib/abstract_controller/base.rb +7 -21
- data/lib/abstract_controller/caching/fragments.rb +2 -2
- data/lib/abstract_controller/caching.rb +1 -1
- data/lib/abstract_controller/callbacks.rb +9 -8
- data/lib/abstract_controller/collector.rb +2 -2
- data/lib/abstract_controller/error.rb +1 -1
- data/lib/abstract_controller/helpers.rb +3 -2
- data/lib/abstract_controller/logger.rb +1 -1
- data/lib/abstract_controller/railties/routes_helpers.rb +2 -0
- data/lib/abstract_controller/translation.rb +0 -2
- data/lib/abstract_controller/url_for.rb +4 -6
- data/lib/action_controller/api.rb +1 -1
- data/lib/action_controller/log_subscriber.rb +3 -1
- data/lib/action_controller/metal/conditional_get.rb +38 -1
- data/lib/action_controller/metal/content_security_policy.rb +1 -1
- 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/http_authentication.rb +15 -16
- data/lib/action_controller/metal/instrumentation.rb +55 -52
- data/lib/action_controller/metal/live.rb +42 -2
- data/lib/action_controller/metal/mime_responds.rb +3 -3
- data/lib/action_controller/metal/params_wrapper.rb +7 -7
- data/lib/action_controller/metal/permissions_policy.rb +1 -1
- data/lib/action_controller/metal/query_tags.rb +16 -0
- data/lib/action_controller/metal/redirecting.rb +49 -34
- data/lib/action_controller/metal/rendering.rb +9 -9
- data/lib/action_controller/metal/request_forgery_protection.rb +64 -20
- data/lib/action_controller/metal/rescue.rb +1 -1
- data/lib/action_controller/metal/streaming.rb +1 -3
- data/lib/action_controller/metal/strong_parameters.rb +25 -29
- data/lib/action_controller/metal/testing.rb +0 -2
- data/lib/action_controller/metal.rb +7 -10
- data/lib/action_controller/railtie.rb +42 -5
- data/lib/action_controller/test_case.rb +6 -2
- 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 +47 -37
- data/lib/action_dispatch/http/filter_parameters.rb +5 -0
- data/lib/action_dispatch/http/mime_negotiation.rb +13 -3
- data/lib/action_dispatch/http/mime_type.rb +9 -11
- data/lib/action_dispatch/http/parameters.rb +4 -4
- data/lib/action_dispatch/http/permissions_policy.rb +1 -1
- data/lib/action_dispatch/http/request.rb +10 -19
- data/lib/action_dispatch/http/response.rb +3 -3
- data/lib/action_dispatch/http/url.rb +9 -10
- 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 +5 -12
- 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 +27 -31
- 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 +1 -1
- data/lib/action_dispatch/middleware/flash.rb +9 -11
- data/lib/action_dispatch/middleware/host_authorization.rb +25 -73
- data/lib/action_dispatch/middleware/remote_ip.rb +16 -4
- data/lib/action_dispatch/middleware/session/abstract_store.rb +1 -1
- data/lib/action_dispatch/middleware/show_exceptions.rb +6 -18
- data/lib/action_dispatch/middleware/stack.rb +50 -9
- data/lib/action_dispatch/middleware/static.rb +2 -5
- 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 +2 -2
- 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/mapper.rb +44 -72
- data/lib/action_dispatch/routing/redirection.rb +0 -2
- data/lib/action_dispatch/routing/route_set.rb +7 -4
- data/lib/action_dispatch/routing/routes_proxy.rb +1 -1
- data/lib/action_dispatch/routing/url_for.rb +1 -2
- data/lib/action_dispatch/routing.rb +2 -2
- data/lib/action_dispatch/system_test_case.rb +6 -12
- data/lib/action_dispatch/system_testing/driver.rb +24 -4
- data/lib/action_dispatch/system_testing/test_helpers/screenshot_helper.rb +10 -6
- 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 +2 -2
- data/lib/action_dispatch.rb +1 -1
- data/lib/action_pack/gem_version.rb +4 -4
- data/lib/action_pack.rb +1 -1
- metadata +21 -21
@@ -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,7 +145,7 @@ module ActionDispatch
|
|
160
145
|
@blocks = blocks(options_constraints)
|
161
146
|
end
|
162
147
|
|
163
|
-
requirements, conditions = split_constraints path_params, constraints
|
148
|
+
requirements, conditions = split_constraints ast.path_params, constraints
|
164
149
|
verify_regexp_requirements requirements.map(&:last).grep(Regexp)
|
165
150
|
|
166
151
|
formats = normalize_format(formatted)
|
@@ -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
|
@@ -956,7 +922,7 @@ module ActionDispatch
|
|
956
922
|
# namespace :admin, as: "sekret" do
|
957
923
|
# resources :posts
|
958
924
|
# end
|
959
|
-
def namespace(path, options = {})
|
925
|
+
def namespace(path, options = {}, &block)
|
960
926
|
path = path.to_s
|
961
927
|
|
962
928
|
defaults = {
|
@@ -967,7 +933,7 @@ module ActionDispatch
|
|
967
933
|
}
|
968
934
|
|
969
935
|
path_scope(options.delete(:path) { path }) do
|
970
|
-
scope(defaults.merge!(options))
|
936
|
+
scope(defaults.merge!(options), &block)
|
971
937
|
end
|
972
938
|
end
|
973
939
|
|
@@ -1026,8 +992,8 @@ module ActionDispatch
|
|
1026
992
|
# constraints(Iphone) do
|
1027
993
|
# resources :iphones
|
1028
994
|
# end
|
1029
|
-
def constraints(constraints = {})
|
1030
|
-
scope(constraints: constraints)
|
995
|
+
def constraints(constraints = {}, &block)
|
996
|
+
scope(constraints: constraints, &block)
|
1031
997
|
end
|
1032
998
|
|
1033
999
|
# Allows you to set default parameters for a route, such as this:
|
@@ -1156,7 +1122,7 @@ module ActionDispatch
|
|
1156
1122
|
RESOURCE_OPTIONS = [:as, :controller, :path, :only, :except, :param, :concerns]
|
1157
1123
|
CANONICAL_ACTIONS = %w(index create new show update destroy)
|
1158
1124
|
|
1159
|
-
class Resource
|
1125
|
+
class Resource # :nodoc:
|
1160
1126
|
attr_reader :controller, :path, :param
|
1161
1127
|
|
1162
1128
|
def initialize(entities, api_only, shallow, options = {})
|
@@ -1251,7 +1217,7 @@ module ActionDispatch
|
|
1251
1217
|
def singleton?; false; end
|
1252
1218
|
end
|
1253
1219
|
|
1254
|
-
class SingletonResource < Resource
|
1220
|
+
class SingletonResource < Resource # :nodoc:
|
1255
1221
|
def initialize(entities, api_only, shallow, options)
|
1256
1222
|
super
|
1257
1223
|
@as = nil
|
@@ -1307,6 +1273,16 @@ module ActionDispatch
|
|
1307
1273
|
# DELETE /profile
|
1308
1274
|
# POST /profile
|
1309
1275
|
#
|
1276
|
+
# If you want instances of a model to work with this resource via
|
1277
|
+
# record identification (e.g. in +form_with+ or +redirect_to+), you
|
1278
|
+
# will need to call resolve[rdoc-ref:CustomUrls#resolve]:
|
1279
|
+
#
|
1280
|
+
# resource :profile
|
1281
|
+
# resolve('Profile') { [:profile] }
|
1282
|
+
#
|
1283
|
+
# # Enables this to work with singular routes:
|
1284
|
+
# form_with(model: @profile) {}
|
1285
|
+
#
|
1310
1286
|
# === Options
|
1311
1287
|
# Takes same options as resources[rdoc-ref:#resources]
|
1312
1288
|
def resource(*resources, &block)
|
@@ -1517,15 +1493,13 @@ module ActionDispatch
|
|
1517
1493
|
# with GET, and route to the search action of +PhotosController+. It will also
|
1518
1494
|
# create the <tt>search_photos_url</tt> and <tt>search_photos_path</tt>
|
1519
1495
|
# route helpers.
|
1520
|
-
def collection
|
1496
|
+
def collection(&block)
|
1521
1497
|
unless resource_scope?
|
1522
1498
|
raise ArgumentError, "can't use collection outside resource(s) scope"
|
1523
1499
|
end
|
1524
1500
|
|
1525
1501
|
with_scope_level(:collection) do
|
1526
|
-
path_scope(parent_resource.collection_scope)
|
1527
|
-
yield
|
1528
|
-
end
|
1502
|
+
path_scope(parent_resource.collection_scope, &block)
|
1529
1503
|
end
|
1530
1504
|
end
|
1531
1505
|
|
@@ -1540,7 +1514,7 @@ module ActionDispatch
|
|
1540
1514
|
# This will recognize <tt>/photos/1/preview</tt> with GET, and route to the
|
1541
1515
|
# preview action of +PhotosController+. It will also create the
|
1542
1516
|
# <tt>preview_photo_url</tt> and <tt>preview_photo_path</tt> helpers.
|
1543
|
-
def member
|
1517
|
+
def member(&block)
|
1544
1518
|
unless resource_scope?
|
1545
1519
|
raise ArgumentError, "can't use member outside resource(s) scope"
|
1546
1520
|
end
|
@@ -1548,27 +1522,25 @@ module ActionDispatch
|
|
1548
1522
|
with_scope_level(:member) do
|
1549
1523
|
if shallow?
|
1550
1524
|
shallow_scope {
|
1551
|
-
path_scope(parent_resource.member_scope)
|
1525
|
+
path_scope(parent_resource.member_scope, &block)
|
1552
1526
|
}
|
1553
1527
|
else
|
1554
|
-
path_scope(parent_resource.member_scope)
|
1528
|
+
path_scope(parent_resource.member_scope, &block)
|
1555
1529
|
end
|
1556
1530
|
end
|
1557
1531
|
end
|
1558
1532
|
|
1559
|
-
def new
|
1533
|
+
def new(&block)
|
1560
1534
|
unless resource_scope?
|
1561
1535
|
raise ArgumentError, "can't use new outside resource(s) scope"
|
1562
1536
|
end
|
1563
1537
|
|
1564
1538
|
with_scope_level(:new) do
|
1565
|
-
path_scope(parent_resource.new_scope(action_path(:new)))
|
1566
|
-
yield
|
1567
|
-
end
|
1539
|
+
path_scope(parent_resource.new_scope(action_path(:new)), &block)
|
1568
1540
|
end
|
1569
1541
|
end
|
1570
1542
|
|
1571
|
-
def nested
|
1543
|
+
def nested(&block)
|
1572
1544
|
unless resource_scope?
|
1573
1545
|
raise ArgumentError, "can't use nested outside resource(s) scope"
|
1574
1546
|
end
|
@@ -1577,12 +1549,12 @@ module ActionDispatch
|
|
1577
1549
|
if shallow? && shallow_nesting_depth >= 1
|
1578
1550
|
shallow_scope do
|
1579
1551
|
path_scope(parent_resource.nested_scope) do
|
1580
|
-
scope(nested_options)
|
1552
|
+
scope(nested_options, &block)
|
1581
1553
|
end
|
1582
1554
|
end
|
1583
1555
|
else
|
1584
1556
|
path_scope(parent_resource.nested_scope) do
|
1585
|
-
scope(nested_options)
|
1557
|
+
scope(nested_options, &block)
|
1586
1558
|
end
|
1587
1559
|
end
|
1588
1560
|
end
|
@@ -1768,10 +1740,10 @@ module ActionDispatch
|
|
1768
1740
|
@scope = @scope.parent
|
1769
1741
|
end
|
1770
1742
|
|
1771
|
-
def resource_scope(resource)
|
1743
|
+
def resource_scope(resource, &block)
|
1772
1744
|
@scope = @scope.new(scope_level_resource: resource)
|
1773
1745
|
|
1774
|
-
controller(resource.resource_scope)
|
1746
|
+
controller(resource.resource_scope, &block)
|
1775
1747
|
ensure
|
1776
1748
|
@scope = @scope.parent
|
1777
1749
|
end
|
@@ -1889,7 +1861,7 @@ module ActionDispatch
|
|
1889
1861
|
end
|
1890
1862
|
|
1891
1863
|
def map_match(paths, options)
|
1892
|
-
if options[:on] && !VALID_ON_OPTIONS.include?(
|
1864
|
+
if (on = options[:on]) && !VALID_ON_OPTIONS.include?(on)
|
1893
1865
|
raise ArgumentError, "Unknown scope #{on.inspect} given to :on"
|
1894
1866
|
end
|
1895
1867
|
|
@@ -2300,7 +2272,7 @@ module ActionDispatch
|
|
2300
2272
|
NULL = Scope.new(nil, nil)
|
2301
2273
|
end
|
2302
2274
|
|
2303
|
-
def initialize(set)
|
2275
|
+
def initialize(set) # :nodoc:
|
2304
2276
|
@set = set
|
2305
2277
|
@draw_paths = set.draw_paths
|
2306
2278
|
@scope = Scope.new(path_names: @set.resources_path_names)
|
@@ -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
|
|
@@ -824,7 +823,11 @@ module ActionDispatch
|
|
824
823
|
params = route_with_params.params
|
825
824
|
|
826
825
|
if options.key? :params
|
827
|
-
|
826
|
+
if options[:params]&.respond_to?(:to_hash)
|
827
|
+
params.merge! options[:params]
|
828
|
+
else
|
829
|
+
params[:params] = options[:params]
|
830
|
+
end
|
828
831
|
end
|
829
832
|
|
830
833
|
options[:path] = path
|
@@ -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
|
@@ -255,7 +255,7 @@ module ActionDispatch
|
|
255
255
|
autoload :UrlFor
|
256
256
|
autoload :PolymorphicRoutes
|
257
257
|
|
258
|
-
SEPARATORS = %w( / . ? )
|
259
|
-
HTTP_METHODS = [:get, :head, :post, :patch, :put, :delete, :options]
|
258
|
+
SEPARATORS = %w( / . ? ) # :nodoc:
|
259
|
+
HTTP_METHODS = [:get, :head, :post, :patch, :put, :delete, :options] # :nodoc:
|
260
260
|
end
|
261
261
|
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
|
#
|
@@ -115,8 +115,6 @@ module ActionDispatch
|
|
115
115
|
include SystemTesting::TestHelpers::SetupAndTeardown
|
116
116
|
include SystemTesting::TestHelpers::ScreenshotHelper
|
117
117
|
|
118
|
-
DEFAULT_HOST = "http://127.0.0.1"
|
119
|
-
|
120
118
|
def initialize(*) # :nodoc:
|
121
119
|
super
|
122
120
|
self.class.driven_by(:selenium) unless self.class.driver?
|
@@ -142,7 +140,7 @@ module ActionDispatch
|
|
142
140
|
#
|
143
141
|
# Examples:
|
144
142
|
#
|
145
|
-
# driven_by :
|
143
|
+
# driven_by :cuprite
|
146
144
|
#
|
147
145
|
# driven_by :selenium, screen_size: [800, 800]
|
148
146
|
#
|
@@ -168,11 +166,7 @@ module ActionDispatch
|
|
168
166
|
include ActionDispatch.test_app.routes.mounted_helpers
|
169
167
|
|
170
168
|
def url_options
|
171
|
-
default_url_options.reverse_merge(host: app_host)
|
172
|
-
end
|
173
|
-
|
174
|
-
def app_host
|
175
|
-
Capybara.app_host || Capybara.current_session.server_url || DEFAULT_HOST
|
169
|
+
default_url_options.reverse_merge(host: Capybara.app_host || Capybara.current_session.server_url)
|
176
170
|
end
|
177
171
|
end.new
|
178
172
|
end
|
@@ -5,14 +5,24 @@ module ActionDispatch
|
|
5
5
|
class Driver # :nodoc:
|
6
6
|
def initialize(name, **options, &capabilities)
|
7
7
|
@name = name
|
8
|
-
@browser = Browser.new(options[:using])
|
9
8
|
@screen_size = options[:screen_size]
|
10
9
|
@options = options[:options] || {}
|
11
10
|
@capabilities = capabilities
|
12
11
|
|
12
|
+
if [:poltergeist, :webkit].include?(name)
|
13
|
+
ActiveSupport::Deprecation.warn <<~MSG.squish
|
14
|
+
Poltergeist and capybara-webkit are not maintained already.
|
15
|
+
Driver registration of :poltergeist or :webkit is deprecated and will be removed in Rails 7.1.
|
16
|
+
You can still use :selenium, and also :cuprite is available for alternative to Poltergeist.
|
17
|
+
MSG
|
18
|
+
end
|
19
|
+
|
13
20
|
if name == :selenium
|
14
21
|
require "selenium/webdriver"
|
22
|
+
@browser = Browser.new(options[:using])
|
15
23
|
@browser.preload
|
24
|
+
else
|
25
|
+
@browser = nil
|
16
26
|
end
|
17
27
|
end
|
18
28
|
|
@@ -24,17 +34,19 @@ module ActionDispatch
|
|
24
34
|
|
25
35
|
private
|
26
36
|
def registerable?
|
27
|
-
[:selenium, :poltergeist, :webkit].include?(@name)
|
37
|
+
[:selenium, :poltergeist, :webkit, :cuprite, :rack_test].include?(@name)
|
28
38
|
end
|
29
39
|
|
30
40
|
def register
|
31
|
-
@browser
|
41
|
+
@browser&.configure(&@capabilities)
|
32
42
|
|
33
43
|
Capybara.register_driver @name do |app|
|
34
44
|
case @name
|
35
45
|
when :selenium then register_selenium(app)
|
36
46
|
when :poltergeist then register_poltergeist(app)
|
37
47
|
when :webkit then register_webkit(app)
|
48
|
+
when :cuprite then register_cuprite(app)
|
49
|
+
when :rack_test then register_rack_test(app)
|
38
50
|
end
|
39
51
|
end
|
40
52
|
end
|
@@ -44,7 +56,7 @@ module ActionDispatch
|
|
44
56
|
end
|
45
57
|
|
46
58
|
def register_selenium(app)
|
47
|
-
Capybara::Selenium::Driver.new(app,
|
59
|
+
Capybara::Selenium::Driver.new(app, browser: @browser.type, **browser_options).tap do |driver|
|
48
60
|
driver.browser.manage.window.size = Selenium::WebDriver::Dimension.new(*@screen_size)
|
49
61
|
end
|
50
62
|
end
|
@@ -59,6 +71,14 @@ module ActionDispatch
|
|
59
71
|
end
|
60
72
|
end
|
61
73
|
|
74
|
+
def register_cuprite(app)
|
75
|
+
Capybara::Cuprite::Driver.new(app, @options.merge(window_size: @screen_size))
|
76
|
+
end
|
77
|
+
|
78
|
+
def register_rack_test(app)
|
79
|
+
Capybara::RackTest::Driver.new(app, respect_data_method: true, **@options)
|
80
|
+
end
|
81
|
+
|
62
82
|
def setup
|
63
83
|
Capybara.current_driver = @name
|
64
84
|
end
|
@@ -15,8 +15,11 @@ module ActionDispatch
|
|
15
15
|
#
|
16
16
|
# The screenshot will be displayed in your console, if supported.
|
17
17
|
#
|
18
|
+
# The default screenshots directory is +tmp/screenshots+ but you can set a different
|
19
|
+
# one with +Capybara.save_path+
|
20
|
+
#
|
18
21
|
# You can set the +RAILS_SYSTEM_TESTING_SCREENSHOT_HTML+ environment variable to
|
19
|
-
# save the HTML from the page that is being
|
22
|
+
# save the HTML from the page that is being screenshotted so you can investigate the
|
20
23
|
# elements on the page at the time of the screenshot
|
21
24
|
#
|
22
25
|
# You can set the +RAILS_SYSTEM_TESTING_SCREENSHOT+ environment variable to
|
@@ -37,10 +40,7 @@ module ActionDispatch
|
|
37
40
|
# Takes a screenshot of the current page in the browser if the test
|
38
41
|
# failed.
|
39
42
|
#
|
40
|
-
# +take_failed_screenshot+ is
|
41
|
-
# that is generated with the application. To take screenshots when a test
|
42
|
-
# fails add +take_failed_screenshot+ to the teardown block before clearing
|
43
|
-
# sessions.
|
43
|
+
# +take_failed_screenshot+ is called during system test teardown.
|
44
44
|
def take_failed_screenshot
|
45
45
|
take_screenshot if failed? && supports_screenshot?
|
46
46
|
end
|
@@ -76,7 +76,11 @@ module ActionDispatch
|
|
76
76
|
end
|
77
77
|
|
78
78
|
def absolute_path
|
79
|
-
Rails.root.join(
|
79
|
+
Rails.root.join(screenshots_dir, image_name)
|
80
|
+
end
|
81
|
+
|
82
|
+
def screenshots_dir
|
83
|
+
Capybara.save_path.presence || "tmp/screenshots"
|
80
84
|
end
|
81
85
|
|
82
86
|
def absolute_image_path
|
@@ -1,14 +1,11 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require "rails-dom-testing"
|
4
|
+
require "action_dispatch/testing/assertions/response"
|
5
|
+
require "action_dispatch/testing/assertions/routing"
|
4
6
|
|
5
7
|
module ActionDispatch
|
6
8
|
module Assertions
|
7
|
-
autoload :ResponseAssertions, "action_dispatch/testing/assertions/response"
|
8
|
-
autoload :RoutingAssertions, "action_dispatch/testing/assertions/routing"
|
9
|
-
|
10
|
-
extend ActiveSupport::Concern
|
11
|
-
|
12
9
|
include ResponseAssertions
|
13
10
|
include RoutingAssertions
|
14
11
|
include Rails::Dom::Testing::Assertions
|
@@ -8,7 +8,7 @@ require "minitest"
|
|
8
8
|
require "action_dispatch/testing/request_encoder"
|
9
9
|
|
10
10
|
module ActionDispatch
|
11
|
-
module Integration
|
11
|
+
module Integration # :nodoc:
|
12
12
|
module RequestHelpers
|
13
13
|
# Performs a GET request with the given parameters. See ActionDispatch::Integration::Session#process
|
14
14
|
# for more details.
|
@@ -199,7 +199,7 @@ module ActionDispatch
|
|
199
199
|
# merged into the Rack env hash.
|
200
200
|
# - +env+: Additional env to pass, as a Hash. The headers will be
|
201
201
|
# merged into the Rack env hash.
|
202
|
-
# - +xhr+: Set to +true+ if you want to make
|
202
|
+
# - +xhr+: Set to +true+ if you want to make an Ajax request.
|
203
203
|
# Adds request headers characteristic of XMLHttpRequest e.g. HTTP_X_REQUESTED_WITH.
|
204
204
|
# The headers will be merged into the Rack env hash.
|
205
205
|
# - +as+: Used for encoding the request with different content type.
|
@@ -363,13 +363,11 @@ module ActionDispatch
|
|
363
363
|
reset_html_document = "@html_document = nil"
|
364
364
|
end
|
365
365
|
|
366
|
-
definition = RUBY_VERSION >= "2.7" ? "..." : "*args"
|
367
|
-
|
368
366
|
module_eval <<~RUBY, __FILE__, __LINE__ + 1
|
369
|
-
def #{method}(
|
367
|
+
def #{method}(...)
|
370
368
|
#{reset_html_document}
|
371
369
|
|
372
|
-
result = integration_session.#{method}(
|
370
|
+
result = integration_session.#{method}(...)
|
373
371
|
copy_session_variables!
|
374
372
|
result
|
375
373
|
end
|
@@ -404,7 +402,7 @@ module ActionDispatch
|
|
404
402
|
|
405
403
|
# Copy the instance variables from the current session instance into the
|
406
404
|
# test instance.
|
407
|
-
def copy_session_variables!
|
405
|
+
def copy_session_variables! # :nodoc:
|
408
406
|
@controller = @integration_session.controller
|
409
407
|
@response = @integration_session.response
|
410
408
|
@request = @integration_session.request
|
@@ -433,7 +431,7 @@ module ActionDispatch
|
|
433
431
|
super
|
434
432
|
end
|
435
433
|
end
|
436
|
-
ruby2_keywords(:method_missing)
|
434
|
+
ruby2_keywords(:method_missing)
|
437
435
|
end
|
438
436
|
end
|
439
437
|
|
@@ -8,14 +8,14 @@ module ActionDispatch
|
|
8
8
|
module FixtureFile
|
9
9
|
# Shortcut for <tt>Rack::Test::UploadedFile.new(File.join(ActionDispatch::IntegrationTest.file_fixture_path, path), type)</tt>:
|
10
10
|
#
|
11
|
-
# post :change_avatar, params: { avatar: fixture_file_upload('
|
11
|
+
# post :change_avatar, params: { avatar: fixture_file_upload('david.png', 'image/png') }
|
12
12
|
#
|
13
13
|
# Default fixture files location is <tt>test/fixtures/files</tt>.
|
14
14
|
#
|
15
15
|
# To upload binary files on Windows, pass <tt>:binary</tt> as the last parameter.
|
16
16
|
# This will not affect other platforms:
|
17
17
|
#
|
18
|
-
# post :change_avatar, params: { avatar: fixture_file_upload('
|
18
|
+
# post :change_avatar, params: { avatar: fixture_file_upload('david.png', 'image/png', :binary) }
|
19
19
|
def fixture_file_upload(path, mime_type = nil, binary = false)
|
20
20
|
if self.class.respond_to?(:fixture_path) && self.class.fixture_path &&
|
21
21
|
!File.exist?(path)
|
data/lib/action_dispatch.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
#--
|
4
|
-
# Copyright (c) 2004-
|
4
|
+
# Copyright (c) 2004-2021 David Heinemeier Hansson
|
5
5
|
#
|
6
6
|
# Permission is hereby granted, free of charge, to any person obtaining
|
7
7
|
# a copy of this software and associated documentation files (the
|
data/lib/action_pack.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
#--
|
4
|
-
# Copyright (c) 2004-
|
4
|
+
# Copyright (c) 2004-2021 David Heinemeier Hansson
|
5
5
|
#
|
6
6
|
# Permission is hereby granted, free of charge, to any person obtaining
|
7
7
|
# a copy of this software and associated documentation files (the
|