actionpack 5.1.0.beta1 → 5.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 +29 -2
- data/lib/action_controller/api.rb +3 -4
- data/lib/action_controller/base.rb +4 -4
- data/lib/action_controller/metal.rb +2 -2
- data/lib/action_controller/metal/etag_with_flash.rb +2 -2
- data/lib/action_controller/metal/force_ssl.rb +7 -7
- data/lib/action_controller/metal/http_authentication.rb +1 -1
- data/lib/action_controller/metal/implicit_render.rb +3 -3
- data/lib/action_controller/metal/instrumentation.rb +1 -1
- data/lib/action_controller/metal/live.rb +4 -4
- data/lib/action_controller/metal/mime_responds.rb +2 -2
- data/lib/action_controller/metal/parameter_encoding.rb +1 -1
- data/lib/action_controller/metal/params_wrapper.rb +4 -4
- data/lib/action_controller/metal/redirecting.rb +5 -2
- data/lib/action_controller/metal/rendering.rb +1 -1
- data/lib/action_controller/metal/request_forgery_protection.rb +5 -5
- data/lib/action_controller/metal/rescue.rb +1 -1
- data/lib/action_controller/metal/streaming.rb +1 -1
- data/lib/action_controller/metal/strong_parameters.rb +95 -9
- data/lib/action_controller/metal/url_for.rb +1 -1
- data/lib/action_controller/railtie.rb +1 -1
- data/lib/action_controller/renderer.rb +4 -3
- data/lib/action_controller/test_case.rb +5 -5
- data/lib/action_dispatch/routing/mapper.rb +2 -2
- data/lib/action_dispatch/routing/polymorphic_routes.rb +4 -4
- data/lib/action_dispatch/routing/redirection.rb +2 -0
- data/lib/action_dispatch/routing/route_set.rb +18 -23
- data/lib/action_dispatch/routing/url_for.rb +8 -0
- data/lib/action_dispatch/system_test_case.rb +14 -7
- data/lib/action_dispatch/system_testing/driver.rb +20 -4
- data/lib/action_dispatch/system_testing/test_helpers/screenshot_helper.rb +39 -6
- data/lib/action_dispatch/system_testing/test_helpers/setup_and_teardown.rb +1 -1
- data/lib/action_dispatch/testing/integration.rb +5 -6
- data/lib/action_pack/gem_version.rb +1 -1
- metadata +8 -9
- data/lib/action_dispatch/system_testing/browser.rb +0 -28
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e2d161d451c124876c1a7514f155780ba418d16e
|
4
|
+
data.tar.gz: f22881573e854eac0be7c4727d5f1289a7d849e9
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d5c053839dd73ab090207928e1a5635c31bf637425f2d875d1dd6d26366d3b23e66e0c7004b4577e38b9049a9b9511c0ca3aa8d679c24784db2e0452bcdc1667
|
7
|
+
data.tar.gz: 9dd0e7bc6a77d7f84ed680c0298ba3d6d890eb679a0b912a0206e286d536cdee8f1ac6ab53fb1b49e938180a0ff625a6e3189b623d79bdbb082404f683569b90
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,30 @@
|
|
1
|
+
## Rails 5.1.0.rc1 (March 20, 2017) ##
|
2
|
+
|
3
|
+
* Fix `NameError` raised in `ActionController::Renderer#with_defaults`
|
4
|
+
|
5
|
+
*Hiroyuki Ishii*
|
6
|
+
|
7
|
+
* Added `#reverse_merge` and `#reverse_merge!` methods to `ActionController::Parameters`
|
8
|
+
|
9
|
+
*Edouard Chin*, *Mitsutaka Mimura*
|
10
|
+
|
11
|
+
* Fix malformed URLS when using `ApplicationController.renderer`
|
12
|
+
|
13
|
+
The Rack environment variable `rack.url_scheme` was not being set so `scheme` was
|
14
|
+
returning `nil`. This caused URLs to be malformed with the default settings.
|
15
|
+
Fix this by setting `rack.url_scheme` when the environment is normalized.
|
16
|
+
|
17
|
+
Fixes #28151.
|
18
|
+
|
19
|
+
*George Vrettos*
|
20
|
+
|
21
|
+
* Commit flash changes when using a redirect route.
|
22
|
+
|
23
|
+
Fixes #27992.
|
24
|
+
|
25
|
+
*Andrew White*
|
26
|
+
|
27
|
+
|
1
28
|
## Rails 5.1.0.beta1 (February 23, 2017) ##
|
2
29
|
|
3
30
|
* Prefer `remove_method` over `undef_method` when reloading routes
|
@@ -13,7 +40,7 @@
|
|
13
40
|
|
14
41
|
``` ruby
|
15
42
|
resource :basket
|
16
|
-
resolve(
|
43
|
+
resolve("Basket") { [:basket] }
|
17
44
|
```
|
18
45
|
|
19
46
|
``` erb
|
@@ -308,7 +335,7 @@
|
|
308
335
|
redirects to
|
309
336
|
POST https://example.com/articles (i.e. ArticlesContoller#create)
|
310
337
|
|
311
|
-
|
338
|
+
*Chirag Singhal*
|
312
339
|
|
313
340
|
* Add `:as` option to `ActionController:TestCase#process` and related methods.
|
314
341
|
|
@@ -81,10 +81,9 @@ module ActionController
|
|
81
81
|
# end
|
82
82
|
# end
|
83
83
|
#
|
84
|
-
#
|
85
|
-
#
|
86
|
-
#
|
87
|
-
# out of the box.
|
84
|
+
# Make sure to check the modules included in <tt>ActionController::Base</tt>
|
85
|
+
# if you want to use any other functionality that is not provided
|
86
|
+
# by <tt>ActionController::API</tt> out of the box.
|
88
87
|
class API < Metal
|
89
88
|
abstract!
|
90
89
|
|
@@ -8,7 +8,7 @@ module ActionController
|
|
8
8
|
# on the controller, which will automatically be made accessible to the web-server through \Rails Routes.
|
9
9
|
#
|
10
10
|
# By default, only the ApplicationController in a \Rails application inherits from <tt>ActionController::Base</tt>. All other
|
11
|
-
# controllers
|
11
|
+
# controllers inherit from ApplicationController. This gives you one class to configure things such as
|
12
12
|
# request forgery protection and filtering of sensitive request parameters.
|
13
13
|
#
|
14
14
|
# A sample controller could look like this:
|
@@ -30,7 +30,7 @@ module ActionController
|
|
30
30
|
#
|
31
31
|
# Unlike index, the create action will not render a template. After performing its main purpose (creating a
|
32
32
|
# new post), it initiates a redirect instead. This redirect works by returning an external
|
33
|
-
#
|
33
|
+
# <tt>302 Moved</tt> HTTP response that takes the user to the index action.
|
34
34
|
#
|
35
35
|
# These two methods represent the two basic action archetypes used in Action Controllers: Get-and-show and do-and-redirect.
|
36
36
|
# Most actions are variations on these themes.
|
@@ -59,7 +59,7 @@ module ActionController
|
|
59
59
|
# <input type="text" name="post[name]" value="david">
|
60
60
|
# <input type="text" name="post[address]" value="hyacintvej">
|
61
61
|
#
|
62
|
-
# A request
|
62
|
+
# A request coming from a form holding these inputs will include <tt>{ "post" => { "name" => "david", "address" => "hyacintvej" } }</tt>.
|
63
63
|
# If the address input had been named <tt>post[address][street]</tt>, the <tt>params</tt> would have included
|
64
64
|
# <tt>{ "post" => { "address" => { "street" => "hyacintvej" } } }</tt>. There's no limit to the depth of the nesting.
|
65
65
|
#
|
@@ -74,7 +74,7 @@ module ActionController
|
|
74
74
|
#
|
75
75
|
# session[:person] = Person.authenticate(user_name, password)
|
76
76
|
#
|
77
|
-
#
|
77
|
+
# You can retrieve it again through the same hash:
|
78
78
|
#
|
79
79
|
# Hello #{session[:person]}
|
80
80
|
#
|
@@ -138,7 +138,7 @@ module ActionController
|
|
138
138
|
false
|
139
139
|
end
|
140
140
|
|
141
|
-
# Delegates to the class' <tt>controller_name</tt
|
141
|
+
# Delegates to the class' <tt>controller_name</tt>.
|
142
142
|
def controller_name
|
143
143
|
self.class.controller_name
|
144
144
|
end
|
@@ -244,7 +244,7 @@ module ActionController
|
|
244
244
|
end
|
245
245
|
end
|
246
246
|
|
247
|
-
# Direct dispatch to the controller.
|
247
|
+
# Direct dispatch to the controller. Instantiates the controller, then
|
248
248
|
# executes the action named +name+.
|
249
249
|
def self.dispatch(name, req, res)
|
250
250
|
if middleware_stack.any?
|
@@ -1,9 +1,9 @@
|
|
1
1
|
module ActionController
|
2
2
|
# When you're using the flash, it's generally used as a conditional on the view.
|
3
3
|
# This means the content of the view depends on the flash. Which in turn means
|
4
|
-
# that the
|
4
|
+
# that the ETag for a response should be computed with the content of the flash
|
5
5
|
# in mind. This does that by including the content of the flash as a component
|
6
|
-
# in the
|
6
|
+
# in the ETag that's generated for a response.
|
7
7
|
module EtagWithFlash
|
8
8
|
extend ActiveSupport::Concern
|
9
9
|
|
@@ -2,17 +2,17 @@ require "active_support/core_ext/hash/except"
|
|
2
2
|
require "active_support/core_ext/hash/slice"
|
3
3
|
|
4
4
|
module ActionController
|
5
|
-
# This module provides a method which will redirect the browser to use HTTPS
|
6
|
-
# protocol. This will ensure that
|
5
|
+
# This module provides a method which will redirect the browser to use the secured HTTPS
|
6
|
+
# protocol. This will ensure that users' sensitive information will be
|
7
7
|
# transferred safely over the internet. You _should_ always force the browser
|
8
8
|
# to use HTTPS when you're transferring sensitive information such as
|
9
9
|
# user authentication, account information, or credit card information.
|
10
10
|
#
|
11
11
|
# Note that if you are really concerned about your application security,
|
12
12
|
# you might consider using +config.force_ssl+ in your config file instead.
|
13
|
-
# That will ensure all the data transferred via HTTPS
|
14
|
-
# the user from getting their session hijacked when accessing the
|
15
|
-
# unsecured HTTP protocol.
|
13
|
+
# That will ensure all the data is transferred via HTTPS, and will
|
14
|
+
# prevent the user from getting their session hijacked when accessing the
|
15
|
+
# site over unsecured HTTP protocol.
|
16
16
|
module ForceSSL
|
17
17
|
extend ActiveSupport::Concern
|
18
18
|
include AbstractController::Callbacks
|
@@ -23,7 +23,7 @@ module ActionController
|
|
23
23
|
|
24
24
|
module ClassMethods
|
25
25
|
# Force the request to this particular controller or specified actions to be
|
26
|
-
#
|
26
|
+
# through the HTTPS protocol.
|
27
27
|
#
|
28
28
|
# If you need to disable this for any reason (e.g. development) then you can use
|
29
29
|
# an +:if+ or +:unless+ condition.
|
@@ -71,7 +71,7 @@ module ActionController
|
|
71
71
|
# Redirect the existing request to use the HTTPS protocol.
|
72
72
|
#
|
73
73
|
# ==== Parameters
|
74
|
-
# * <tt>host_or_options</tt> - Either a host name or any of the url
|
74
|
+
# * <tt>host_or_options</tt> - Either a host name or any of the url and
|
75
75
|
# redirect options available to the <tt>force_ssl</tt> method.
|
76
76
|
def force_ssl_redirect(host_or_options = nil)
|
77
77
|
unless request.ssl?
|
@@ -445,7 +445,7 @@ module ActionController
|
|
445
445
|
end
|
446
446
|
end
|
447
447
|
|
448
|
-
# Parses the token and options out of the token
|
448
|
+
# Parses the token and options out of the token Authorization header.
|
449
449
|
# The value for the Authorization header is expected to have the prefix
|
450
450
|
# <tt>"Token"</tt> or <tt>"Bearer"</tt>. If the header looks like this:
|
451
451
|
# Authorization: Token token="abc", nonce="def"
|
@@ -2,11 +2,11 @@ module ActionController
|
|
2
2
|
# Handles implicit rendering for a controller action that does not
|
3
3
|
# explicitly respond with +render+, +respond_to+, +redirect+, or +head+.
|
4
4
|
#
|
5
|
-
# For API controllers, the implicit response is always 204 No Content
|
5
|
+
# For API controllers, the implicit response is always <tt>204 No Content</tt>.
|
6
6
|
#
|
7
7
|
# For all other controllers, we use these heuristics to decide whether to
|
8
8
|
# render a template, raise an error for a missing template, or respond with
|
9
|
-
# 204 No Content
|
9
|
+
# <tt>204 No Content</tt>:
|
10
10
|
#
|
11
11
|
# First, if we DO find a template, it's rendered. Template lookup accounts
|
12
12
|
# for the action name, locales, format, variant, template handlers, and more
|
@@ -23,7 +23,7 @@ module ActionController
|
|
23
23
|
# <tt>ActionView::UnknownFormat</tt> with an explanation.
|
24
24
|
#
|
25
25
|
# Finally, if we DON'T find a template AND the request isn't a browser page
|
26
|
-
# load, then we implicitly respond with 204 No Content
|
26
|
+
# load, then we implicitly respond with <tt>204 No Content</tt>.
|
27
27
|
module ImplicitRender
|
28
28
|
# :stopdoc:
|
29
29
|
include BasicImplicitRender
|
@@ -3,7 +3,7 @@ require "abstract_controller/logger"
|
|
3
3
|
|
4
4
|
module ActionController
|
5
5
|
# Adds instrumentation to several ends in ActionController::Base. It also provides
|
6
|
-
# some hooks related with process_action
|
6
|
+
# some hooks related with process_action. This allows an ORM like Active Record
|
7
7
|
# and/or DataMapper to plug in ActionController and show related information.
|
8
8
|
#
|
9
9
|
# Check ActiveRecord::Railties::ControllerRuntime for an example.
|
@@ -239,8 +239,8 @@ module ActionController
|
|
239
239
|
|
240
240
|
error = nil
|
241
241
|
# This processes the action in a child thread. It lets us return the
|
242
|
-
# response code and headers back up the
|
243
|
-
# the body in parallel with sending data to the client
|
242
|
+
# response code and headers back up the Rack stack, and still process
|
243
|
+
# the body in parallel with sending data to the client.
|
244
244
|
new_controller_thread {
|
245
245
|
ActiveSupport::Dependencies.interlock.running do
|
246
246
|
t2 = Thread.current
|
@@ -278,9 +278,9 @@ module ActionController
|
|
278
278
|
raise error if error
|
279
279
|
end
|
280
280
|
|
281
|
-
# Spawn a new thread to serve up the controller in.
|
281
|
+
# Spawn a new thread to serve up the controller in. This is to get
|
282
282
|
# around the fact that Rack isn't based around IOs and we need to use
|
283
|
-
# a thread to stream data from the response bodies.
|
283
|
+
# a thread to stream data from the response bodies. Nobody should call
|
284
284
|
# this method except in Rails internals. Seriously!
|
285
285
|
def new_controller_thread # :nodoc:
|
286
286
|
Thread.new {
|
@@ -181,8 +181,8 @@ module ActionController #:nodoc:
|
|
181
181
|
#
|
182
182
|
# request.variant = [:tablet, :phone]
|
183
183
|
#
|
184
|
-
#
|
185
|
-
# +:tablet+ variant declared, +:phone+ variant will be picked:
|
184
|
+
# This will work similarly to formats and MIME types negotiation. If there
|
185
|
+
# is no +:tablet+ variant declared, +:phone+ variant will be picked:
|
186
186
|
#
|
187
187
|
# respond_to do |format|
|
188
188
|
# format.html.none
|
@@ -39,7 +39,7 @@ module ActionController
|
|
39
39
|
# end
|
40
40
|
#
|
41
41
|
# The show action in the above controller would have all parameter values
|
42
|
-
# encoded as ASCII-8BIT.
|
42
|
+
# encoded as ASCII-8BIT. This is useful in the case where an application
|
43
43
|
# must handle data but encoding of the data is unknown, like file system data.
|
44
44
|
def skip_parameter_encoding(action)
|
45
45
|
@_parameter_encodings[action.to_s] = true
|
@@ -213,7 +213,7 @@ module ActionController
|
|
213
213
|
end
|
214
214
|
|
215
215
|
# Sets the default wrapper key or model which will be used to determine
|
216
|
-
# wrapper key and attribute names.
|
216
|
+
# wrapper key and attribute names. Called automatically when the
|
217
217
|
# module is inherited.
|
218
218
|
def inherited(klass)
|
219
219
|
if klass._wrapper_options.format.any?
|
@@ -225,7 +225,7 @@ module ActionController
|
|
225
225
|
end
|
226
226
|
end
|
227
227
|
|
228
|
-
# Performs parameters wrapping upon the request.
|
228
|
+
# Performs parameters wrapping upon the request. Called automatically
|
229
229
|
# by the metal call stack.
|
230
230
|
def process_action(*args)
|
231
231
|
if _wrapper_enabled?
|
@@ -238,11 +238,11 @@ module ActionController
|
|
238
238
|
wrapped_keys = request.request_parameters.keys
|
239
239
|
wrapped_filtered_hash = _wrap_parameters request.filtered_parameters.slice(*wrapped_keys)
|
240
240
|
|
241
|
-
# This will make the wrapped hash accessible from controller and view
|
241
|
+
# This will make the wrapped hash accessible from controller and view.
|
242
242
|
request.parameters.merge! wrapped_hash
|
243
243
|
request.request_parameters.merge! wrapped_hash
|
244
244
|
|
245
|
-
# This will display the wrapped hash in the log file
|
245
|
+
# This will display the wrapped hash in the log file.
|
246
246
|
request.filtered_parameters.merge! wrapped_filtered_hash
|
247
247
|
end
|
248
248
|
super
|
@@ -22,7 +22,7 @@ module ActionController
|
|
22
22
|
# redirect_to posts_url
|
23
23
|
# redirect_to proc { edit_post_url(@post) }
|
24
24
|
#
|
25
|
-
# The redirection happens as a
|
25
|
+
# The redirection happens as a <tt>302 Found</tt> header unless otherwise specified using the <tt>:status</tt> option:
|
26
26
|
#
|
27
27
|
# redirect_to post_url(@post), status: :found
|
28
28
|
# redirect_to action: 'atom', status: :moved_permanently
|
@@ -36,7 +36,7 @@ module ActionController
|
|
36
36
|
# If you are using XHR requests other than GET or POST and redirecting after the
|
37
37
|
# request then some browsers will follow the redirect using the original request
|
38
38
|
# method. This may lead to undesirable behavior such as a double DELETE. To work
|
39
|
-
# around this
|
39
|
+
# around this you can return a <tt>303 See Other</tt> status code which will be
|
40
40
|
# followed using a GET request.
|
41
41
|
#
|
42
42
|
# redirect_to posts_url, status: :see_other
|
@@ -50,6 +50,9 @@ module ActionController
|
|
50
50
|
# redirect_to post_url(@post), status: 301, flash: { updated_post_id: @post.id }
|
51
51
|
# redirect_to({ action: 'atom' }, alert: "Something serious happened")
|
52
52
|
#
|
53
|
+
# Statements after +redirect_to+ in our controller get executed, so +redirect_to+ doesn't stop the execution of the function.
|
54
|
+
# To terminate the execution of the function immediately after the +redirect_to+, use return.
|
55
|
+
# redirect_to post_url(@post) and return
|
53
56
|
def redirect_to(options = {}, response_status = {})
|
54
57
|
raise ActionControllerError.new("Cannot redirect to nil!") unless options
|
55
58
|
raise AbstractController::DoubleRenderError if response_body
|
@@ -36,7 +36,7 @@ module ActionController
|
|
36
36
|
super
|
37
37
|
end
|
38
38
|
|
39
|
-
# Overwrite render_to_string because body can now be set to a
|
39
|
+
# Overwrite render_to_string because body can now be set to a Rack body.
|
40
40
|
def render_to_string(*)
|
41
41
|
result = super
|
42
42
|
if result.respond_to?(:each)
|
@@ -262,9 +262,9 @@ module ActionController #:nodoc:
|
|
262
262
|
|
263
263
|
# Returns true or false if a request is verified. Checks:
|
264
264
|
#
|
265
|
-
# * Is it a GET or HEAD request?
|
265
|
+
# * Is it a GET or HEAD request? GETs should be safe and idempotent
|
266
266
|
# * Does the form_authenticity_token match the given token value from the params?
|
267
|
-
# * Does the X-CSRF-Token header match the form_authenticity_token
|
267
|
+
# * Does the X-CSRF-Token header match the form_authenticity_token?
|
268
268
|
def verified_request? # :doc:
|
269
269
|
!protect_against_forgery? || request.get? || request.head? ||
|
270
270
|
(valid_request_origin? && any_authenticity_token_valid?)
|
@@ -327,7 +327,7 @@ module ActionController #:nodoc:
|
|
327
327
|
if masked_token.length == AUTHENTICITY_TOKEN_LENGTH
|
328
328
|
# This is actually an unmasked token. This is expected if
|
329
329
|
# you have just upgraded to masked tokens, but should stop
|
330
|
-
# happening shortly after installing this gem
|
330
|
+
# happening shortly after installing this gem.
|
331
331
|
compare_with_real_token masked_token, session
|
332
332
|
|
333
333
|
elsif masked_token.length == AUTHENTICITY_TOKEN_LENGTH * 2
|
@@ -336,13 +336,13 @@ module ActionController #:nodoc:
|
|
336
336
|
compare_with_real_token(csrf_token, session) ||
|
337
337
|
valid_per_form_csrf_token?(csrf_token, session)
|
338
338
|
else
|
339
|
-
false # Token is malformed
|
339
|
+
false # Token is malformed.
|
340
340
|
end
|
341
341
|
end
|
342
342
|
|
343
343
|
def unmask_token(masked_token) # :doc:
|
344
344
|
# Split the token into the one-time pad and the encrypted
|
345
|
-
# value and decrypt it
|
345
|
+
# value and decrypt it.
|
346
346
|
one_time_pad = masked_token[0...AUTHENTICITY_TOKEN_LENGTH]
|
347
347
|
encrypted_csrf_token = masked_token[AUTHENTICITY_TOKEN_LENGTH..-1]
|
348
348
|
xor_byte_strings(one_time_pad, encrypted_csrf_token)
|
@@ -10,7 +10,7 @@ module ActionController #:nodoc:
|
|
10
10
|
# exceptions must be shown. This method is only called when
|
11
11
|
# consider_all_requests_local is false. By default, it returns
|
12
12
|
# false, but someone may set it to `request.local?` so local
|
13
|
-
# requests in production still
|
13
|
+
# requests in production still show the detailed exception pages.
|
14
14
|
def show_detailed_exceptions?
|
15
15
|
false
|
16
16
|
end
|
@@ -3,7 +3,7 @@ require "rack/chunked"
|
|
3
3
|
module ActionController #:nodoc:
|
4
4
|
# Allows views to be streamed back to the client as they are rendered.
|
5
5
|
#
|
6
|
-
#
|
6
|
+
# By default, Rails renders views by first rendering the template
|
7
7
|
# and then the layout. The response is sent to the client after the whole
|
8
8
|
# template is rendered, all queries are made, and the layout is processed.
|
9
9
|
#
|
@@ -112,6 +112,77 @@ module ActionController
|
|
112
112
|
|
113
113
|
cattr_accessor :action_on_unpermitted_parameters, instance_accessor: false
|
114
114
|
|
115
|
+
##
|
116
|
+
# :method: as_json
|
117
|
+
#
|
118
|
+
# :call-seq:
|
119
|
+
# as_json(options=nil)
|
120
|
+
#
|
121
|
+
# Returns a hash that can be used as the JSON representation for the parameters.
|
122
|
+
|
123
|
+
##
|
124
|
+
# :method: empty?
|
125
|
+
#
|
126
|
+
# :call-seq:
|
127
|
+
# empty?()
|
128
|
+
#
|
129
|
+
# Returns true if the parameters have no key/value pairs.
|
130
|
+
|
131
|
+
##
|
132
|
+
# :method: has_key?
|
133
|
+
#
|
134
|
+
# :call-seq:
|
135
|
+
# has_key?(key)
|
136
|
+
#
|
137
|
+
# Returns true if the given key is present in the parameters.
|
138
|
+
|
139
|
+
##
|
140
|
+
# :method: has_value?
|
141
|
+
#
|
142
|
+
# :call-seq:
|
143
|
+
# has_value?(value)
|
144
|
+
#
|
145
|
+
# Returns true if the given value is present for some key in the parameters.
|
146
|
+
|
147
|
+
##
|
148
|
+
# :method: include?
|
149
|
+
#
|
150
|
+
# :call-seq:
|
151
|
+
# include?(key)
|
152
|
+
#
|
153
|
+
# Returns true if the given key is present in the parameters.
|
154
|
+
|
155
|
+
##
|
156
|
+
# :method: key?
|
157
|
+
#
|
158
|
+
# :call-seq:
|
159
|
+
# key?(key)
|
160
|
+
#
|
161
|
+
# Returns true if the given key is present in the parameters.
|
162
|
+
|
163
|
+
##
|
164
|
+
# :method: keys
|
165
|
+
#
|
166
|
+
# :call-seq:
|
167
|
+
# keys()
|
168
|
+
#
|
169
|
+
# Returns a new array of the keys of the parameters.
|
170
|
+
|
171
|
+
##
|
172
|
+
# :method: value?
|
173
|
+
#
|
174
|
+
# :call-seq:
|
175
|
+
# value?(value)
|
176
|
+
#
|
177
|
+
# Returns true if the given value is present for some key in the parameters.
|
178
|
+
|
179
|
+
##
|
180
|
+
# :method: values
|
181
|
+
#
|
182
|
+
# :call-seq:
|
183
|
+
# values()
|
184
|
+
#
|
185
|
+
# Returns a new array of the values of the parameters.
|
115
186
|
delegate :keys, :key?, :has_key?, :values, :has_value?, :value?, :empty?, :include?,
|
116
187
|
:as_json, to: :@parameters
|
117
188
|
|
@@ -191,7 +262,7 @@ module ActionController
|
|
191
262
|
alias_method :to_unsafe_hash, :to_unsafe_h
|
192
263
|
|
193
264
|
# Convert all hashes in values into parameters, then yield each pair in
|
194
|
-
# the same way as <tt>Hash#each_pair</tt
|
265
|
+
# the same way as <tt>Hash#each_pair</tt>.
|
195
266
|
def each_pair(&block)
|
196
267
|
@parameters.each_pair do |key, value|
|
197
268
|
yield key, convert_hashes_to_parameters(key, value)
|
@@ -339,7 +410,7 @@ module ActionController
|
|
339
410
|
#
|
340
411
|
# params.permit(preferences: {})
|
341
412
|
#
|
342
|
-
#
|
413
|
+
# Be careful because this opens the door to arbitrary input. In this
|
343
414
|
# case, +permit+ ensures values in the returned structure are permitted
|
344
415
|
# scalars and filters out anything else.
|
345
416
|
#
|
@@ -575,20 +646,35 @@ module ActionController
|
|
575
646
|
end
|
576
647
|
|
577
648
|
# Returns a new <tt>ActionController::Parameters</tt> with all keys from
|
578
|
-
# +other_hash+
|
649
|
+
# +other_hash+ merged into current hash.
|
579
650
|
def merge(other_hash)
|
580
651
|
new_instance_with_inherited_permitted_status(
|
581
652
|
@parameters.merge(other_hash.to_h)
|
582
653
|
)
|
583
654
|
end
|
584
655
|
|
585
|
-
# Returns current <tt>ActionController::Parameters</tt> instance
|
586
|
-
# +other_hash+
|
656
|
+
# Returns current <tt>ActionController::Parameters</tt> instance with
|
657
|
+
# +other_hash+ merged into current hash.
|
587
658
|
def merge!(other_hash)
|
588
659
|
@parameters.merge!(other_hash.to_h)
|
589
660
|
self
|
590
661
|
end
|
591
662
|
|
663
|
+
# Returns a new <tt>ActionController::Parameters</tt> with all keys from
|
664
|
+
# current hash merged into +other_hash+.
|
665
|
+
def reverse_merge(other_hash)
|
666
|
+
new_instance_with_inherited_permitted_status(
|
667
|
+
other_hash.to_h.merge(@parameters)
|
668
|
+
)
|
669
|
+
end
|
670
|
+
|
671
|
+
# Returns current <tt>ActionController::Parameters</tt> instance with
|
672
|
+
# current hash merged into +other_hash+.
|
673
|
+
def reverse_merge!(other_hash)
|
674
|
+
@parameters.merge!(other_hash.to_h) { |key, left, right| left }
|
675
|
+
self
|
676
|
+
end
|
677
|
+
|
592
678
|
# This is required by ActiveModel attribute assignment, so that user can
|
593
679
|
# pass +Parameters+ to a mass assignment methods in a model. It should not
|
594
680
|
# matter as we are using +HashWithIndifferentAccess+ internally.
|
@@ -629,7 +715,7 @@ module ActionController
|
|
629
715
|
|
630
716
|
undef_method :to_param
|
631
717
|
|
632
|
-
# Returns duplicate of object including all parameters
|
718
|
+
# Returns duplicate of object including all parameters.
|
633
719
|
def deep_dup
|
634
720
|
self.class.new(@parameters.deep_dup).tap do |duplicate|
|
635
721
|
duplicate.permitted = @permitted
|
@@ -849,7 +935,7 @@ module ActionController
|
|
849
935
|
# whitelisted.
|
850
936
|
#
|
851
937
|
# In addition, parameters can be marked as required and flow through a
|
852
|
-
# predefined raise/rescue flow to end up as a 400 Bad Request with no
|
938
|
+
# predefined raise/rescue flow to end up as a <tt>400 Bad Request</tt> with no
|
853
939
|
# effort.
|
854
940
|
#
|
855
941
|
# class PeopleController < ActionController::Base
|
@@ -862,7 +948,7 @@ module ActionController
|
|
862
948
|
# end
|
863
949
|
#
|
864
950
|
# # This will pass with flying colors as long as there's a person key in the
|
865
|
-
# # parameters, otherwise it'll raise an ActionController::
|
951
|
+
# # parameters, otherwise it'll raise an ActionController::ParameterMissing
|
866
952
|
# # exception, which will get caught by ActionController::Base and turned
|
867
953
|
# # into a 400 Bad Request reply.
|
868
954
|
# def update
|
@@ -873,7 +959,7 @@ module ActionController
|
|
873
959
|
#
|
874
960
|
# private
|
875
961
|
# # Using a private method to encapsulate the permissible parameters is
|
876
|
-
# #
|
962
|
+
# # a good pattern since you'll be able to reuse the same permit
|
877
963
|
# # list between create and update. Also, you can specialize this method
|
878
964
|
# # with per-user checking of permissible attributes.
|
879
965
|
# def person_params
|
@@ -3,7 +3,7 @@ module ActionController
|
|
3
3
|
# the <tt>_routes</tt> method. Otherwise, an exception will be raised.
|
4
4
|
#
|
5
5
|
# In addition to <tt>AbstractController::UrlFor</tt>, this module accesses the HTTP layer to define
|
6
|
-
#
|
6
|
+
# URL options like the +host+. In order to do so, this module requires the host class
|
7
7
|
# to implement +env+ which needs to be Rack-compatible and +request+
|
8
8
|
# which is either an instance of +ActionDispatch::Request+ or an object
|
9
9
|
# that responds to the +host+, +optional_port+, +protocol+ and
|
@@ -42,7 +42,7 @@ module ActionController
|
|
42
42
|
options.javascripts_dir ||= paths["public/javascripts"].first
|
43
43
|
options.stylesheets_dir ||= paths["public/stylesheets"].first
|
44
44
|
|
45
|
-
# Ensure readers methods get compiled
|
45
|
+
# Ensure readers methods get compiled.
|
46
46
|
options.asset_host ||= app.config.asset_host
|
47
47
|
options.relative_url_root ||= app.config.relative_url_root
|
48
48
|
|
@@ -5,7 +5,7 @@ module ActionController
|
|
5
5
|
# without requirement of being in controller actions.
|
6
6
|
#
|
7
7
|
# You get a concrete renderer class by invoking ActionController::Base#renderer.
|
8
|
-
# For example
|
8
|
+
# For example:
|
9
9
|
#
|
10
10
|
# ApplicationController.renderer
|
11
11
|
#
|
@@ -18,7 +18,7 @@ module ActionController
|
|
18
18
|
# ApplicationController.render template: '...'
|
19
19
|
#
|
20
20
|
# #render allows you to use the same options that you can use when rendering in a controller.
|
21
|
-
# For example
|
21
|
+
# For example:
|
22
22
|
#
|
23
23
|
# FooController.render :action, locals: { ... }, assigns: { ... }
|
24
24
|
#
|
@@ -56,7 +56,7 @@ module ActionController
|
|
56
56
|
|
57
57
|
# Create a new renderer for the same controller but with new defaults.
|
58
58
|
def with_defaults(defaults)
|
59
|
-
self.class.new controller, env, self.defaults.merge(defaults)
|
59
|
+
self.class.new controller, @env, self.defaults.merge(defaults)
|
60
60
|
end
|
61
61
|
|
62
62
|
# Accepts a custom Rack environment to render templates in.
|
@@ -85,6 +85,7 @@ module ActionController
|
|
85
85
|
def normalize_keys(env)
|
86
86
|
new_env = {}
|
87
87
|
env.each_pair { |k, v| new_env[rack_key_for(k)] = rack_value_for(k, v) }
|
88
|
+
new_env["rack.url_scheme"] = new_env["HTTPS"] == "on" ? "https" : "http"
|
88
89
|
new_env
|
89
90
|
end
|
90
91
|
|
@@ -13,10 +13,10 @@ module ActionController
|
|
13
13
|
end
|
14
14
|
|
15
15
|
module Live
|
16
|
-
# Disable controller / rendering threads in tests.
|
16
|
+
# Disable controller / rendering threads in tests. User tests can access
|
17
17
|
# the database on the main thread, so they could open a txn, then the
|
18
18
|
# controller thread will open a new connection and try to access data
|
19
|
-
# that's only visible to the main thread's txn.
|
19
|
+
# that's only visible to the main thread's txn. This is the problem in #23483.
|
20
20
|
remove_method :new_controller_thread
|
21
21
|
def new_controller_thread # :nodoc:
|
22
22
|
yield
|
@@ -35,7 +35,7 @@ module ActionController
|
|
35
35
|
|
36
36
|
attr_reader :controller_class
|
37
37
|
|
38
|
-
# Create a new test request with default `env` values
|
38
|
+
# Create a new test request with default `env` values.
|
39
39
|
def self.create(controller_class)
|
40
40
|
env = {}
|
41
41
|
env = Rails.application.env_config.merge(env) if defined?(Rails.application) && Rails.application
|
@@ -131,7 +131,7 @@ module ActionController
|
|
131
131
|
include Rack::Test::Utils
|
132
132
|
|
133
133
|
def should_multipart?(params)
|
134
|
-
# FIXME: lifted from Rack-Test. We should push this separation upstream
|
134
|
+
# FIXME: lifted from Rack-Test. We should push this separation upstream.
|
135
135
|
multipart = false
|
136
136
|
query = lambda { |value|
|
137
137
|
case value
|
@@ -300,7 +300,7 @@ module ActionController
|
|
300
300
|
# assert_equal "Dave", cookies[:name] # makes sure that a cookie called :name was set as "Dave"
|
301
301
|
# assert flash.empty? # makes sure that there's nothing in the flash
|
302
302
|
#
|
303
|
-
# On top of the collections, you have the complete
|
303
|
+
# On top of the collections, you have the complete URL that a given action redirected to available in <tt>redirect_to_url</tt>.
|
304
304
|
#
|
305
305
|
# For redirects within the same controller, you can even call follow_redirect and the redirect will be followed, triggering another
|
306
306
|
# action call which can then be asserted against.
|
@@ -1904,7 +1904,7 @@ module ActionDispatch
|
|
1904
1904
|
ast = Journey::Parser.parse path
|
1905
1905
|
|
1906
1906
|
mapping = Mapping.build(@scope, @set, ast, controller, default_action, to, via, formatted, options_constraints, anchor, options)
|
1907
|
-
@set.add_route(mapping,
|
1907
|
+
@set.add_route(mapping, as)
|
1908
1908
|
end
|
1909
1909
|
|
1910
1910
|
def match_root_route(options)
|
@@ -2054,7 +2054,7 @@ module ActionDispatch
|
|
2054
2054
|
# your url helper definition, e.g:
|
2055
2055
|
#
|
2056
2056
|
# direct :browse, page: 1, size: 10 do |options|
|
2057
|
-
# [ :products, options.merge(params.permit(:page, :size)) ]
|
2057
|
+
# [ :products, options.merge(params.permit(:page, :size).to_h.symbolize_keys) ]
|
2058
2058
|
# end
|
2059
2059
|
#
|
2060
2060
|
# In this instance the `params` object comes from the context in which the the
|
@@ -40,7 +40,7 @@ module ActionDispatch
|
|
40
40
|
#
|
41
41
|
# Example usage:
|
42
42
|
#
|
43
|
-
# edit_polymorphic_path(@post)
|
43
|
+
# edit_polymorphic_path(@post) # => "/posts/1/edit"
|
44
44
|
# polymorphic_path(@post, format: :pdf) # => "/posts/1.pdf"
|
45
45
|
#
|
46
46
|
# == Usage with mounted engines
|
@@ -104,7 +104,7 @@ module ActionDispatch
|
|
104
104
|
end
|
105
105
|
|
106
106
|
if mapping = polymorphic_mapping(record_or_hash_or_array)
|
107
|
-
return mapping.call(self, [record_or_hash_or_array, options])
|
107
|
+
return mapping.call(self, [record_or_hash_or_array, options], false)
|
108
108
|
end
|
109
109
|
|
110
110
|
opts = options.dup
|
@@ -128,7 +128,7 @@ module ActionDispatch
|
|
128
128
|
end
|
129
129
|
|
130
130
|
if mapping = polymorphic_mapping(record_or_hash_or_array)
|
131
|
-
return mapping.call(self, [record_or_hash_or_array, options],
|
131
|
+
return mapping.call(self, [record_or_hash_or_array, options], true)
|
132
132
|
end
|
133
133
|
|
134
134
|
opts = options.dup
|
@@ -273,7 +273,7 @@ module ActionDispatch
|
|
273
273
|
|
274
274
|
def handle_model_call(target, record)
|
275
275
|
if mapping = polymorphic_mapping(target, record)
|
276
|
-
mapping.call(target, [record],
|
276
|
+
mapping.call(target, [record], suffix == "path")
|
277
277
|
else
|
278
278
|
method, args = handle_model(record)
|
279
279
|
target.send(method, *args)
|
@@ -36,6 +36,8 @@ module ActionDispatch
|
|
36
36
|
uri.host ||= req.host
|
37
37
|
uri.port ||= req.port unless req.standard_port?
|
38
38
|
|
39
|
+
req.commit_flash
|
40
|
+
|
39
41
|
body = %(<html><body>You are being <a href="#{ERB::Util.unwrapped_html_escape(uri.to_s)}">redirected</a>.</body></html>)
|
40
42
|
|
41
43
|
headers = {
|
@@ -164,13 +164,13 @@ module ActionDispatch
|
|
164
164
|
|
165
165
|
@path_helpers_module.module_eval do
|
166
166
|
define_method(:"#{name}_path") do |*args|
|
167
|
-
helper.call(self, args,
|
167
|
+
helper.call(self, args, true)
|
168
168
|
end
|
169
169
|
end
|
170
170
|
|
171
171
|
@url_helpers_module.module_eval do
|
172
172
|
define_method(:"#{name}_url") do |*args|
|
173
|
-
helper.call(self, args)
|
173
|
+
helper.call(self, args, false)
|
174
174
|
end
|
175
175
|
end
|
176
176
|
end
|
@@ -509,6 +509,14 @@ module ActionDispatch
|
|
509
509
|
@_proxy.url_for(options)
|
510
510
|
end
|
511
511
|
|
512
|
+
def full_url_for(options)
|
513
|
+
@_proxy.full_url_for(options)
|
514
|
+
end
|
515
|
+
|
516
|
+
def route_for(name, *args)
|
517
|
+
@_proxy.route_for(name, *args)
|
518
|
+
end
|
519
|
+
|
512
520
|
def optimize_routes_generation?
|
513
521
|
@_proxy.optimize_routes_generation?
|
514
522
|
end
|
@@ -565,7 +573,7 @@ module ActionDispatch
|
|
565
573
|
routes.empty?
|
566
574
|
end
|
567
575
|
|
568
|
-
def add_route(mapping,
|
576
|
+
def add_route(mapping, name)
|
569
577
|
raise ArgumentError, "Invalid route name: '#{name}'" unless name.blank? || name.to_s.match(/^[_a-z]\w*$/i)
|
570
578
|
|
571
579
|
if name && named_routes[name]
|
@@ -613,26 +621,14 @@ module ActionDispatch
|
|
613
621
|
@block = block
|
614
622
|
end
|
615
623
|
|
616
|
-
def call(t, args,
|
624
|
+
def call(t, args, only_path = false)
|
617
625
|
options = args.extract_options!
|
618
|
-
|
619
|
-
|
620
|
-
|
621
|
-
|
622
|
-
t.url_for(url_options)
|
623
|
-
when Hash
|
624
|
-
t.url_for(url_options.merge(outer_options))
|
625
|
-
when ActionController::Parameters
|
626
|
-
if url_options.permitted?
|
627
|
-
t.url_for(url_options.to_h.merge(outer_options))
|
628
|
-
else
|
629
|
-
raise ArgumentError, "Generating a URL from non sanitized request parameters is insecure!"
|
630
|
-
end
|
631
|
-
when Array
|
632
|
-
opts = url_options.extract_options!
|
633
|
-
t.url_for(url_options.push(opts.merge(outer_options)))
|
626
|
+
url = t.full_url_for(eval_block(t, args, options))
|
627
|
+
|
628
|
+
if only_path
|
629
|
+
"/" + url.partition(%r{(?<!/)/(?!/)}).last
|
634
630
|
else
|
635
|
-
|
631
|
+
url
|
636
632
|
end
|
637
633
|
end
|
638
634
|
|
@@ -860,8 +856,7 @@ module ActionDispatch
|
|
860
856
|
params[key] = URI.parser.unescape(value)
|
861
857
|
end
|
862
858
|
end
|
863
|
-
|
864
|
-
req.path_parameters = old_params.merge params
|
859
|
+
req.path_parameters = params
|
865
860
|
app = route.app
|
866
861
|
if app.matches?(req) && app.dispatcher?
|
867
862
|
begin
|
@@ -164,6 +164,10 @@ module ActionDispatch
|
|
164
164
|
# implicitly used by +url_for+ can always be overwritten like shown on the
|
165
165
|
# last +url_for+ calls.
|
166
166
|
def url_for(options = nil)
|
167
|
+
full_url_for(options)
|
168
|
+
end
|
169
|
+
|
170
|
+
def full_url_for(options = nil) # :nodoc:
|
167
171
|
case options
|
168
172
|
when nil
|
169
173
|
_routes.url_for(url_options.symbolize_keys)
|
@@ -192,6 +196,10 @@ module ActionDispatch
|
|
192
196
|
end
|
193
197
|
end
|
194
198
|
|
199
|
+
def route_for(name, *args) # :nodoc:
|
200
|
+
public_send(:"#{name}_url", *args)
|
201
|
+
end
|
202
|
+
|
195
203
|
protected
|
196
204
|
|
197
205
|
def optimize_routes_generation?
|
@@ -1,8 +1,8 @@
|
|
1
1
|
require "capybara/dsl"
|
2
|
+
require "capybara/minitest"
|
2
3
|
require "action_controller"
|
3
4
|
require "action_dispatch/system_testing/driver"
|
4
5
|
require "action_dispatch/system_testing/server"
|
5
|
-
require "action_dispatch/system_testing/browser"
|
6
6
|
require "action_dispatch/system_testing/test_helpers/screenshot_helper"
|
7
7
|
require "action_dispatch/system_testing/test_helpers/setup_and_teardown"
|
8
8
|
|
@@ -81,15 +81,23 @@ module ActionDispatch
|
|
81
81
|
# tests as long as you include the required gems and files.
|
82
82
|
class SystemTestCase < IntegrationTest
|
83
83
|
include Capybara::DSL
|
84
|
+
include Capybara::Minitest::Assertions
|
84
85
|
include SystemTesting::TestHelpers::SetupAndTeardown
|
85
86
|
include SystemTesting::TestHelpers::ScreenshotHelper
|
86
87
|
|
88
|
+
def initialize(*) # :nodoc:
|
89
|
+
super
|
90
|
+
self.class.superclass.driver.use
|
91
|
+
end
|
92
|
+
|
87
93
|
def self.start_application # :nodoc:
|
88
94
|
Capybara.app = Rack::Builder.new do
|
89
95
|
map "/" do
|
90
96
|
run Rails.application
|
91
97
|
end
|
92
98
|
end
|
99
|
+
|
100
|
+
SystemTesting::Server.new.run
|
93
101
|
end
|
94
102
|
|
95
103
|
# System Test configuration options
|
@@ -104,14 +112,13 @@ module ActionDispatch
|
|
104
112
|
# driven_by :selenium, using: :firefox
|
105
113
|
#
|
106
114
|
# driven_by :selenium, screen_size: [800, 800]
|
107
|
-
def self.driven_by(driver, using: :chrome, screen_size: [1400, 1400])
|
108
|
-
SystemTesting::Driver.new(driver)
|
109
|
-
SystemTesting::Server.new.run
|
110
|
-
SystemTesting::Browser.new(using, screen_size).run if selenium?(driver)
|
115
|
+
def self.driven_by(driver, using: :chrome, screen_size: [1400, 1400], options: {})
|
116
|
+
@driver = SystemTesting::Driver.new(driver, using: using, screen_size: screen_size, options: options)
|
111
117
|
end
|
112
118
|
|
113
|
-
|
114
|
-
|
119
|
+
# Returns the driver object for the initialized system test
|
120
|
+
def self.driver
|
121
|
+
@driver ||= SystemTestCase.driven_by(:selenium)
|
115
122
|
end
|
116
123
|
end
|
117
124
|
|
@@ -1,17 +1,33 @@
|
|
1
1
|
module ActionDispatch
|
2
2
|
module SystemTesting
|
3
3
|
class Driver # :nodoc:
|
4
|
-
def initialize(name)
|
4
|
+
def initialize(name, **options)
|
5
5
|
@name = name
|
6
|
+
@browser = options[:using]
|
7
|
+
@screen_size = options[:screen_size]
|
8
|
+
@options = options[:options]
|
6
9
|
end
|
7
10
|
|
8
|
-
def
|
9
|
-
register
|
11
|
+
def use
|
12
|
+
register if selenium?
|
13
|
+
setup
|
10
14
|
end
|
11
15
|
|
12
16
|
private
|
17
|
+
def selenium?
|
18
|
+
@name == :selenium
|
19
|
+
end
|
20
|
+
|
13
21
|
def register
|
14
|
-
Capybara.
|
22
|
+
Capybara.register_driver @name do |app|
|
23
|
+
Capybara::Selenium::Driver.new(app, { browser: @browser }.merge(@options)).tap do |driver|
|
24
|
+
driver.browser.manage.window.size = Selenium::WebDriver::Dimension.new(*@screen_size)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def setup
|
30
|
+
Capybara.current_driver = @name
|
15
31
|
end
|
16
32
|
end
|
17
33
|
end
|
@@ -8,9 +8,20 @@ module ActionDispatch
|
|
8
8
|
# +take_screenshot+ can be used at any point in your system tests to take
|
9
9
|
# a screenshot of the current state. This can be useful for debugging or
|
10
10
|
# automating visual testing.
|
11
|
+
#
|
12
|
+
# The screenshot will be displayed in your console, if supported.
|
13
|
+
#
|
14
|
+
# You can set the +RAILS_SYSTEM_TESTING_SCREENSHOT+ environment variable to
|
15
|
+
# control the output. Possible values are:
|
16
|
+
# * [+inline+ (default)] display the screenshot in the terminal using the
|
17
|
+
# iTerm image protocol (http://iterm2.com/documentation-images.html).
|
18
|
+
# * [+simple+] only display the screenshot path.
|
19
|
+
# This is the default value if the +CI+ environment variables
|
20
|
+
# is defined.
|
21
|
+
# * [+artifact+] display the screenshot in the terminal, using the terminal
|
22
|
+
# artifact format (http://buildkite.github.io/terminal/inline-images/).
|
11
23
|
def take_screenshot
|
12
24
|
save_image
|
13
|
-
puts "[Screenshot]: #{image_path}"
|
14
25
|
puts display_image
|
15
26
|
end
|
16
27
|
|
@@ -22,7 +33,7 @@ module ActionDispatch
|
|
22
33
|
# fails add +take_failed_screenshot+ to the teardown block before clearing
|
23
34
|
# sessions.
|
24
35
|
def take_failed_screenshot
|
25
|
-
take_screenshot if failed?
|
36
|
+
take_screenshot if failed? && supports_screenshot?
|
26
37
|
end
|
27
38
|
|
28
39
|
private
|
@@ -38,14 +49,32 @@ module ActionDispatch
|
|
38
49
|
page.save_screenshot(Rails.root.join(image_path))
|
39
50
|
end
|
40
51
|
|
52
|
+
def output_type
|
53
|
+
# Environment variables have priority
|
54
|
+
output_type = ENV["RAILS_SYSTEM_TESTING_SCREENSHOT"] || ENV["CAPYBARA_INLINE_SCREENSHOT"]
|
55
|
+
|
56
|
+
# If running in a CI environment, default to simple
|
57
|
+
output_type ||= "simple" if ENV["CI"]
|
58
|
+
|
59
|
+
# Default
|
60
|
+
output_type ||= "inline"
|
61
|
+
|
62
|
+
output_type
|
63
|
+
end
|
64
|
+
|
41
65
|
def display_image
|
42
|
-
|
43
|
-
|
44
|
-
|
66
|
+
message = "[Screenshot]: #{image_path}\n"
|
67
|
+
|
68
|
+
case output_type
|
69
|
+
when "artifact"
|
70
|
+
message << "\e]1338;url=artifact://#{image_path}\a\n"
|
71
|
+
when "inline"
|
45
72
|
name = inline_base64(File.basename(image_path))
|
46
73
|
image = inline_base64(File.read(image_path))
|
47
|
-
"\e]1337;File=name=#{name};height=400px;inline=1:#{image}\a"
|
74
|
+
message << "\e]1337;File=name=#{name};height=400px;inline=1:#{image}\a\n"
|
48
75
|
end
|
76
|
+
|
77
|
+
message
|
49
78
|
end
|
50
79
|
|
51
80
|
def inline_base64(path)
|
@@ -55,6 +84,10 @@ module ActionDispatch
|
|
55
84
|
def failed?
|
56
85
|
!passed? && !skipped?
|
57
86
|
end
|
87
|
+
|
88
|
+
def supports_screenshot?
|
89
|
+
Capybara.current_driver != :rack_test
|
90
|
+
end
|
58
91
|
end
|
59
92
|
end
|
60
93
|
end
|
@@ -192,11 +192,10 @@ module ActionDispatch
|
|
192
192
|
# HTTP methods in integration tests. +#process+ is only required when using a
|
193
193
|
# request method that doesn't have a method defined in the integration tests.
|
194
194
|
#
|
195
|
-
# This method returns
|
196
|
-
#
|
197
|
-
#
|
198
|
-
#
|
199
|
-
# response object.
|
195
|
+
# This method returns the response status, after performing the request.
|
196
|
+
# Furthermore, if this method was called from an ActionDispatch::IntegrationTest object,
|
197
|
+
# then that object's <tt>@response</tt> instance variable will point to a Response object
|
198
|
+
# which one can use to inspect the details of the response.
|
200
199
|
#
|
201
200
|
# Example:
|
202
201
|
# process :get, '/author', params: { since: 201501011400 }
|
@@ -572,7 +571,7 @@ module ActionDispatch
|
|
572
571
|
# end
|
573
572
|
#
|
574
573
|
# assert_response :success
|
575
|
-
# assert_equal({ id:
|
574
|
+
# assert_equal({ id: Article.last.id, title: "Ahoy!" }, response.parsed_body)
|
576
575
|
# end
|
577
576
|
# end
|
578
577
|
#
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: actionpack
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 5.1.0.
|
4
|
+
version: 5.1.0.rc1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- David Heinemeier Hansson
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-
|
11
|
+
date: 2017-03-20 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
@@ -16,14 +16,14 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - '='
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: 5.1.0.
|
19
|
+
version: 5.1.0.rc1
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - '='
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: 5.1.0.
|
26
|
+
version: 5.1.0.rc1
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: rack
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -92,28 +92,28 @@ dependencies:
|
|
92
92
|
requirements:
|
93
93
|
- - '='
|
94
94
|
- !ruby/object:Gem::Version
|
95
|
-
version: 5.1.0.
|
95
|
+
version: 5.1.0.rc1
|
96
96
|
type: :runtime
|
97
97
|
prerelease: false
|
98
98
|
version_requirements: !ruby/object:Gem::Requirement
|
99
99
|
requirements:
|
100
100
|
- - '='
|
101
101
|
- !ruby/object:Gem::Version
|
102
|
-
version: 5.1.0.
|
102
|
+
version: 5.1.0.rc1
|
103
103
|
- !ruby/object:Gem::Dependency
|
104
104
|
name: activemodel
|
105
105
|
requirement: !ruby/object:Gem::Requirement
|
106
106
|
requirements:
|
107
107
|
- - '='
|
108
108
|
- !ruby/object:Gem::Version
|
109
|
-
version: 5.1.0.
|
109
|
+
version: 5.1.0.rc1
|
110
110
|
type: :development
|
111
111
|
prerelease: false
|
112
112
|
version_requirements: !ruby/object:Gem::Requirement
|
113
113
|
requirements:
|
114
114
|
- - '='
|
115
115
|
- !ruby/object:Gem::Version
|
116
|
-
version: 5.1.0.
|
116
|
+
version: 5.1.0.rc1
|
117
117
|
description: Web apps on Rails. Simple, battle-tested conventions for building and
|
118
118
|
testing MVC web applications. Works with any Rack-compatible server.
|
119
119
|
email: david@loudthinking.com
|
@@ -267,7 +267,6 @@ files:
|
|
267
267
|
- lib/action_dispatch/routing/routes_proxy.rb
|
268
268
|
- lib/action_dispatch/routing/url_for.rb
|
269
269
|
- lib/action_dispatch/system_test_case.rb
|
270
|
-
- lib/action_dispatch/system_testing/browser.rb
|
271
270
|
- lib/action_dispatch/system_testing/driver.rb
|
272
271
|
- lib/action_dispatch/system_testing/server.rb
|
273
272
|
- lib/action_dispatch/system_testing/test_helpers/screenshot_helper.rb
|
@@ -1,28 +0,0 @@
|
|
1
|
-
module ActionDispatch
|
2
|
-
module SystemTesting
|
3
|
-
class Browser # :nodoc:
|
4
|
-
def initialize(name, screen_size)
|
5
|
-
@name = name
|
6
|
-
@screen_size = screen_size
|
7
|
-
end
|
8
|
-
|
9
|
-
def run
|
10
|
-
register
|
11
|
-
setup
|
12
|
-
end
|
13
|
-
|
14
|
-
private
|
15
|
-
def register
|
16
|
-
Capybara.register_driver @name do |app|
|
17
|
-
Capybara::Selenium::Driver.new(app, browser: @name).tap do |driver|
|
18
|
-
driver.browser.manage.window.size = Selenium::WebDriver::Dimension.new(*@screen_size)
|
19
|
-
end
|
20
|
-
end
|
21
|
-
end
|
22
|
-
|
23
|
-
def setup
|
24
|
-
Capybara.default_driver = @name.to_sym
|
25
|
-
end
|
26
|
-
end
|
27
|
-
end
|
28
|
-
end
|