actionpack 4.2.10 → 5.2.4.6
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 +5 -5
- data/CHANGELOG.md +300 -466
- data/MIT-LICENSE +1 -1
- data/README.rdoc +6 -7
- data/lib/abstract_controller/asset_paths.rb +2 -0
- data/lib/abstract_controller/base.rb +45 -49
- data/lib/{action_controller → abstract_controller}/caching/fragments.rb +78 -15
- data/lib/abstract_controller/caching.rb +66 -0
- data/lib/abstract_controller/callbacks.rb +47 -31
- data/lib/abstract_controller/collector.rb +8 -11
- data/lib/abstract_controller/error.rb +6 -0
- data/lib/abstract_controller/helpers.rb +25 -25
- data/lib/abstract_controller/logger.rb +2 -0
- data/lib/abstract_controller/railties/routes_helpers.rb +4 -2
- data/lib/abstract_controller/rendering.rb +42 -41
- data/lib/abstract_controller/translation.rb +10 -7
- data/lib/abstract_controller/url_for.rb +2 -0
- data/lib/abstract_controller.rb +12 -5
- data/lib/action_controller/api/api_rendering.rb +16 -0
- data/lib/action_controller/api.rb +149 -0
- data/lib/action_controller/base.rb +27 -19
- data/lib/action_controller/caching.rb +14 -57
- data/lib/action_controller/form_builder.rb +50 -0
- data/lib/action_controller/log_subscriber.rb +10 -15
- data/lib/action_controller/metal/basic_implicit_render.rb +13 -0
- data/lib/action_controller/metal/conditional_get.rb +118 -44
- data/lib/action_controller/metal/content_security_policy.rb +52 -0
- data/lib/action_controller/metal/cookies.rb +3 -3
- data/lib/action_controller/metal/data_streaming.rb +27 -46
- data/lib/action_controller/metal/etag_with_flash.rb +18 -0
- data/lib/action_controller/metal/etag_with_template_digest.rb +20 -13
- data/lib/action_controller/metal/exceptions.rb +8 -14
- data/lib/action_controller/metal/flash.rb +4 -3
- data/lib/action_controller/metal/force_ssl.rb +23 -21
- data/lib/action_controller/metal/head.rb +21 -19
- data/lib/action_controller/metal/helpers.rb +24 -14
- data/lib/action_controller/metal/http_authentication.rb +65 -58
- data/lib/action_controller/metal/implicit_render.rb +62 -8
- data/lib/action_controller/metal/instrumentation.rb +19 -21
- data/lib/action_controller/metal/live.rb +90 -106
- data/lib/action_controller/metal/mime_responds.rb +33 -46
- data/lib/action_controller/metal/parameter_encoding.rb +51 -0
- data/lib/action_controller/metal/params_wrapper.rb +61 -53
- data/lib/action_controller/metal/redirecting.rb +49 -28
- data/lib/action_controller/metal/renderers.rb +87 -44
- data/lib/action_controller/metal/rendering.rb +72 -50
- data/lib/action_controller/metal/request_forgery_protection.rb +229 -93
- data/lib/action_controller/metal/rescue.rb +9 -16
- data/lib/action_controller/metal/streaming.rb +12 -10
- data/lib/action_controller/metal/strong_parameters.rb +583 -164
- data/lib/action_controller/metal/testing.rb +2 -17
- data/lib/action_controller/metal/url_for.rb +19 -10
- data/lib/action_controller/metal.rb +98 -83
- data/lib/action_controller/railtie.rb +28 -10
- data/lib/action_controller/railties/helpers.rb +2 -0
- data/lib/action_controller/renderer.rb +117 -0
- data/lib/action_controller/template_assertions.rb +11 -0
- data/lib/action_controller/test_case.rb +280 -411
- data/lib/action_controller.rb +29 -21
- data/lib/action_dispatch/http/cache.rb +93 -47
- data/lib/action_dispatch/http/content_security_policy.rb +272 -0
- data/lib/action_dispatch/http/filter_parameters.rb +26 -20
- data/lib/action_dispatch/http/filter_redirect.rb +10 -11
- data/lib/action_dispatch/http/headers.rb +55 -22
- data/lib/action_dispatch/http/mime_negotiation.rb +60 -41
- data/lib/action_dispatch/http/mime_type.rb +134 -121
- data/lib/action_dispatch/http/mime_types.rb +20 -6
- data/lib/action_dispatch/http/parameter_filter.rb +25 -11
- data/lib/action_dispatch/http/parameters.rb +98 -39
- data/lib/action_dispatch/http/rack_cache.rb +2 -0
- data/lib/action_dispatch/http/request.rb +200 -118
- data/lib/action_dispatch/http/response.rb +225 -110
- data/lib/action_dispatch/http/upload.rb +12 -6
- data/lib/action_dispatch/http/url.rb +110 -28
- data/lib/action_dispatch/journey/formatter.rb +55 -32
- data/lib/action_dispatch/journey/gtg/builder.rb +7 -5
- data/lib/action_dispatch/journey/gtg/simulator.rb +3 -9
- data/lib/action_dispatch/journey/gtg/transition_table.rb +17 -16
- data/lib/action_dispatch/journey/nfa/builder.rb +5 -3
- data/lib/action_dispatch/journey/nfa/dot.rb +13 -13
- data/lib/action_dispatch/journey/nfa/simulator.rb +3 -1
- data/lib/action_dispatch/journey/nfa/transition_table.rb +5 -48
- data/lib/action_dispatch/journey/nodes/node.rb +18 -6
- data/lib/action_dispatch/journey/parser.rb +23 -22
- data/lib/action_dispatch/journey/parser.y +3 -2
- data/lib/action_dispatch/journey/parser_extras.rb +12 -4
- data/lib/action_dispatch/journey/path/pattern.rb +50 -44
- data/lib/action_dispatch/journey/route.rb +106 -28
- data/lib/action_dispatch/journey/router/utils.rb +20 -11
- data/lib/action_dispatch/journey/router.rb +35 -23
- data/lib/action_dispatch/journey/routes.rb +18 -16
- data/lib/action_dispatch/journey/scanner.rb +18 -15
- data/lib/action_dispatch/journey/visitors.rb +99 -52
- data/lib/action_dispatch/journey.rb +7 -5
- data/lib/action_dispatch/middleware/callbacks.rb +1 -2
- data/lib/action_dispatch/middleware/cookies.rb +304 -193
- data/lib/action_dispatch/middleware/debug_exceptions.rb +152 -57
- data/lib/action_dispatch/middleware/debug_locks.rb +124 -0
- data/lib/action_dispatch/middleware/exception_wrapper.rb +68 -69
- data/lib/action_dispatch/middleware/executor.rb +21 -0
- data/lib/action_dispatch/middleware/flash.rb +78 -54
- data/lib/action_dispatch/middleware/public_exceptions.rb +27 -25
- data/lib/action_dispatch/middleware/reloader.rb +5 -91
- data/lib/action_dispatch/middleware/remote_ip.rb +41 -31
- data/lib/action_dispatch/middleware/request_id.rb +17 -9
- data/lib/action_dispatch/middleware/session/abstract_store.rb +41 -25
- data/lib/action_dispatch/middleware/session/cache_store.rb +24 -14
- data/lib/action_dispatch/middleware/session/cookie_store.rb +72 -67
- data/lib/action_dispatch/middleware/session/mem_cache_store.rb +8 -2
- data/lib/action_dispatch/middleware/show_exceptions.rb +26 -22
- data/lib/action_dispatch/middleware/ssl.rb +114 -36
- data/lib/action_dispatch/middleware/stack.rb +31 -44
- data/lib/action_dispatch/middleware/static.rb +57 -50
- data/lib/action_dispatch/middleware/templates/rescues/_request_and_response.html.erb +2 -14
- data/lib/action_dispatch/middleware/templates/rescues/{_source.erb → _source.html.erb} +0 -0
- data/lib/action_dispatch/middleware/templates/rescues/_source.text.erb +8 -0
- data/lib/action_dispatch/middleware/templates/rescues/invalid_statement.html.erb +21 -0
- data/lib/action_dispatch/middleware/templates/rescues/invalid_statement.text.erb +13 -0
- data/lib/action_dispatch/middleware/templates/rescues/layout.erb +1 -0
- data/lib/action_dispatch/middleware/templates/rescues/template_error.html.erb +1 -1
- data/lib/action_dispatch/middleware/templates/rescues/template_error.text.erb +1 -1
- data/lib/action_dispatch/middleware/templates/routes/_route.html.erb +4 -4
- data/lib/action_dispatch/middleware/templates/routes/_table.html.erb +64 -64
- data/lib/action_dispatch/railtie.rb +19 -11
- data/lib/action_dispatch/request/session.rb +106 -59
- data/lib/action_dispatch/request/utils.rb +67 -24
- data/lib/action_dispatch/routing/endpoint.rb +9 -2
- data/lib/action_dispatch/routing/inspector.rb +58 -67
- data/lib/action_dispatch/routing/mapper.rb +733 -447
- data/lib/action_dispatch/routing/polymorphic_routes.rb +166 -140
- data/lib/action_dispatch/routing/redirection.rb +36 -26
- data/lib/action_dispatch/routing/route_set.rb +321 -291
- data/lib/action_dispatch/routing/routes_proxy.rb +32 -5
- data/lib/action_dispatch/routing/url_for.rb +65 -25
- data/lib/action_dispatch/routing.rb +17 -18
- data/lib/action_dispatch/system_test_case.rb +147 -0
- data/lib/action_dispatch/system_testing/browser.rb +49 -0
- data/lib/action_dispatch/system_testing/driver.rb +59 -0
- data/lib/action_dispatch/system_testing/server.rb +31 -0
- data/lib/action_dispatch/system_testing/test_helpers/screenshot_helper.rb +96 -0
- data/lib/action_dispatch/system_testing/test_helpers/setup_and_teardown.rb +31 -0
- data/lib/action_dispatch/system_testing/test_helpers/undef_methods.rb +26 -0
- data/lib/action_dispatch/testing/assertion_response.rb +47 -0
- data/lib/action_dispatch/testing/assertions/response.rb +45 -20
- data/lib/action_dispatch/testing/assertions/routing.rb +30 -26
- data/lib/action_dispatch/testing/assertions.rb +6 -4
- data/lib/action_dispatch/testing/integration.rb +347 -209
- data/lib/action_dispatch/testing/request_encoder.rb +55 -0
- data/lib/action_dispatch/testing/test_process.rb +28 -22
- data/lib/action_dispatch/testing/test_request.rb +27 -34
- data/lib/action_dispatch/testing/test_response.rb +35 -7
- data/lib/action_dispatch.rb +27 -19
- data/lib/action_pack/gem_version.rb +5 -3
- data/lib/action_pack/version.rb +3 -1
- data/lib/action_pack.rb +4 -2
- metadata +59 -42
- data/lib/action_controller/metal/hide_actions.rb +0 -40
- data/lib/action_controller/metal/rack_delegation.rb +0 -32
- data/lib/action_controller/middleware.rb +0 -39
- data/lib/action_controller/model_naming.rb +0 -12
- data/lib/action_dispatch/journey/backwards.rb +0 -5
- data/lib/action_dispatch/journey/router/strexp.rb +0 -27
- data/lib/action_dispatch/middleware/params_parser.rb +0 -60
- data/lib/action_dispatch/testing/assertions/dom.rb +0 -3
- data/lib/action_dispatch/testing/assertions/selector.rb +0 -3
- data/lib/action_dispatch/testing/assertions/tag.rb +0 -3
@@ -1,16 +1,16 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
require
|
4
|
-
require
|
5
|
-
require
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "active_support/core_ext/hash/slice"
|
4
|
+
require "active_support/core_ext/hash/except"
|
5
|
+
require "active_support/core_ext/module/anonymous"
|
6
|
+
require "action_dispatch/http/mime_type"
|
6
7
|
|
7
8
|
module ActionController
|
8
9
|
# Wraps the parameters hash into a nested hash. This will allow clients to
|
9
10
|
# submit requests without having to specify any root elements.
|
10
11
|
#
|
11
12
|
# This functionality is enabled in +config/initializers/wrap_parameters.rb+
|
12
|
-
# and can be customized.
|
13
|
-
# need to be created for the functionality to be enabled.
|
13
|
+
# and can be customized.
|
14
14
|
#
|
15
15
|
# You could also turn it on per controller by setting the format array to
|
16
16
|
# a non-empty array:
|
@@ -42,7 +42,7 @@ module ActionController
|
|
42
42
|
# wrap_parameters :person, include: [:username, :password]
|
43
43
|
# end
|
44
44
|
#
|
45
|
-
# On
|
45
|
+
# On Active Record models with no +:include+ or +:exclude+ option set,
|
46
46
|
# it will only wrap the parameters returned by the class method
|
47
47
|
# <tt>attribute_names</tt>.
|
48
48
|
#
|
@@ -73,7 +73,7 @@ module ActionController
|
|
73
73
|
|
74
74
|
EXCLUDE_PARAMETERS = %w(authenticity_token _method utf8)
|
75
75
|
|
76
|
-
require
|
76
|
+
require "mutex_m"
|
77
77
|
|
78
78
|
class Options < Struct.new(:name, :format, :include, :exclude, :klass, :model) # :nodoc:
|
79
79
|
include Mutex_m
|
@@ -86,14 +86,14 @@ module ActionController
|
|
86
86
|
new name, format, include, exclude, nil, nil
|
87
87
|
end
|
88
88
|
|
89
|
-
def initialize(name, format, include, exclude, klass, model) # nodoc
|
89
|
+
def initialize(name, format, include, exclude, klass, model) # :nodoc:
|
90
90
|
super
|
91
91
|
@include_set = include
|
92
92
|
@name_set = name
|
93
93
|
end
|
94
94
|
|
95
95
|
def model
|
96
|
-
super ||
|
96
|
+
super || self.model = _default_wrap_model
|
97
97
|
end
|
98
98
|
|
99
99
|
def include
|
@@ -107,7 +107,19 @@ module ActionController
|
|
107
107
|
|
108
108
|
unless super || exclude
|
109
109
|
if m.respond_to?(:attribute_names) && m.attribute_names.any?
|
110
|
-
|
110
|
+
if m.respond_to?(:stored_attributes) && !m.stored_attributes.empty?
|
111
|
+
self.include = m.attribute_names + m.stored_attributes.values.flatten.map(&:to_s)
|
112
|
+
else
|
113
|
+
self.include = m.attribute_names
|
114
|
+
end
|
115
|
+
|
116
|
+
if m.respond_to?(:nested_attributes_options) && m.nested_attributes_options.keys.any?
|
117
|
+
self.include += m.nested_attributes_options.keys.map do |key|
|
118
|
+
key.to_s.dup.concat("_attributes")
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
self.include
|
111
123
|
end
|
112
124
|
end
|
113
125
|
end
|
@@ -130,35 +142,34 @@ module ActionController
|
|
130
142
|
end
|
131
143
|
|
132
144
|
private
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
145
|
+
# Determine the wrapper model from the controller's name. By convention,
|
146
|
+
# this could be done by trying to find the defined model that has the
|
147
|
+
# same singular name as the controller. For example, +UsersController+
|
148
|
+
# will try to find if the +User+ model exists.
|
149
|
+
#
|
150
|
+
# This method also does namespace lookup. Foo::Bar::UsersController will
|
151
|
+
# try to find Foo::Bar::User, Foo::User and finally User.
|
152
|
+
def _default_wrap_model
|
153
|
+
return nil if klass.anonymous?
|
154
|
+
model_name = klass.name.sub(/Controller$/, "").classify
|
155
|
+
|
156
|
+
begin
|
157
|
+
if model_klass = model_name.safe_constantize
|
158
|
+
model_klass
|
159
|
+
else
|
160
|
+
namespaces = model_name.split("::")
|
161
|
+
namespaces.delete_at(-2)
|
162
|
+
break if namespaces.last == model_name
|
163
|
+
model_name = namespaces.join("::")
|
164
|
+
end
|
165
|
+
end until model_klass
|
154
166
|
|
155
|
-
|
156
|
-
|
167
|
+
model_klass
|
168
|
+
end
|
157
169
|
end
|
158
170
|
|
159
171
|
included do
|
160
|
-
class_attribute :_wrapper_options
|
161
|
-
self._wrapper_options = Options.from_hash(format: [])
|
172
|
+
class_attribute :_wrapper_options, default: Options.from_hash(format: [])
|
162
173
|
end
|
163
174
|
|
164
175
|
module ClassMethods
|
@@ -200,14 +211,14 @@ module ActionController
|
|
200
211
|
when Hash
|
201
212
|
options = name_or_model_or_options
|
202
213
|
when false
|
203
|
-
options = options.merge(:
|
214
|
+
options = options.merge(format: [])
|
204
215
|
when Symbol, String
|
205
|
-
options = options.merge(:
|
216
|
+
options = options.merge(name: name_or_model_or_options)
|
206
217
|
else
|
207
218
|
model = name_or_model_or_options
|
208
219
|
end
|
209
220
|
|
210
|
-
opts
|
221
|
+
opts = Options.from_hash _wrapper_options.to_h.slice(:format).merge(options)
|
211
222
|
opts.model = model
|
212
223
|
opts.klass = self
|
213
224
|
|
@@ -215,7 +226,7 @@ module ActionController
|
|
215
226
|
end
|
216
227
|
|
217
228
|
# Sets the default wrapper key or model which will be used to determine
|
218
|
-
# wrapper key and attribute names.
|
229
|
+
# wrapper key and attribute names. Called automatically when the
|
219
230
|
# module is inherited.
|
220
231
|
def inherited(klass)
|
221
232
|
if klass._wrapper_options.format.any?
|
@@ -227,24 +238,19 @@ module ActionController
|
|
227
238
|
end
|
228
239
|
end
|
229
240
|
|
230
|
-
# Performs parameters wrapping upon the request.
|
241
|
+
# Performs parameters wrapping upon the request. Called automatically
|
231
242
|
# by the metal call stack.
|
232
243
|
def process_action(*args)
|
233
244
|
if _wrapper_enabled?
|
234
|
-
|
235
|
-
wrapped_hash = _extract_parameters(request.parameters)
|
236
|
-
else
|
237
|
-
wrapped_hash = _wrap_parameters request.request_parameters
|
238
|
-
end
|
239
|
-
|
245
|
+
wrapped_hash = _wrap_parameters request.request_parameters
|
240
246
|
wrapped_keys = request.request_parameters.keys
|
241
247
|
wrapped_filtered_hash = _wrap_parameters request.filtered_parameters.slice(*wrapped_keys)
|
242
248
|
|
243
|
-
# This will make the wrapped hash accessible from controller and view
|
249
|
+
# This will make the wrapped hash accessible from controller and view.
|
244
250
|
request.parameters.merge! wrapped_hash
|
245
251
|
request.request_parameters.merge! wrapped_hash
|
246
252
|
|
247
|
-
# This will display the wrapped hash in the log file
|
253
|
+
# This will display the wrapped hash in the log file.
|
248
254
|
request.filtered_parameters.merge! wrapped_filtered_hash
|
249
255
|
end
|
250
256
|
super
|
@@ -252,7 +258,7 @@ module ActionController
|
|
252
258
|
|
253
259
|
private
|
254
260
|
|
255
|
-
# Returns the wrapper key which will be used to
|
261
|
+
# Returns the wrapper key which will be used to store wrapped parameters.
|
256
262
|
def _wrapper_key
|
257
263
|
_wrapper_options.name
|
258
264
|
end
|
@@ -278,8 +284,10 @@ module ActionController
|
|
278
284
|
|
279
285
|
# Checks if we should perform parameters wrapping.
|
280
286
|
def _wrapper_enabled?
|
281
|
-
|
282
|
-
|
287
|
+
return false unless request.has_content_type?
|
288
|
+
|
289
|
+
ref = request.content_mime_type.ref
|
290
|
+
_wrapper_formats.include?(ref) && _wrapper_key && !request.parameters.key?(_wrapper_key)
|
283
291
|
end
|
284
292
|
end
|
285
293
|
end
|
@@ -1,17 +1,10 @@
|
|
1
|
-
|
2
|
-
class RedirectBackError < AbstractController::Error #:nodoc:
|
3
|
-
DEFAULT_MESSAGE = 'No HTTP_REFERER was set in the request to this action, so redirect_to :back could not be called successfully. If this is a test, make sure to specify request.env["HTTP_REFERER"].'
|
4
|
-
|
5
|
-
def initialize(message = nil)
|
6
|
-
super(message || DEFAULT_MESSAGE)
|
7
|
-
end
|
8
|
-
end
|
1
|
+
# frozen_string_literal: true
|
9
2
|
|
3
|
+
module ActionController
|
10
4
|
module Redirecting
|
11
5
|
extend ActiveSupport::Concern
|
12
6
|
|
13
7
|
include AbstractController::Logger
|
14
|
-
include ActionController::RackDelegation
|
15
8
|
include ActionController::UrlFor
|
16
9
|
|
17
10
|
# Redirects the browser to the target specified in +options+. This parameter can be any one of:
|
@@ -21,34 +14,31 @@ module ActionController
|
|
21
14
|
# * <tt>String</tt> starting with <tt>protocol://</tt> (like <tt>http://</tt>) or a protocol relative reference (like <tt>//</tt>) - Is passed straight through as the target for redirection.
|
22
15
|
# * <tt>String</tt> not containing a protocol - The current protocol and host is prepended to the string.
|
23
16
|
# * <tt>Proc</tt> - A block that will be executed in the controller's context. Should return any option accepted by +redirect_to+.
|
24
|
-
# * <tt>:back</tt> - Back to the page that issued the request. Useful for forms that are triggered from multiple places.
|
25
|
-
# Short-hand for <tt>redirect_to(request.env["HTTP_REFERER"])</tt>
|
26
17
|
#
|
27
18
|
# === Examples:
|
28
19
|
#
|
29
20
|
# redirect_to action: "show", id: 5
|
30
|
-
# redirect_to post
|
21
|
+
# redirect_to @post
|
31
22
|
# redirect_to "http://www.rubyonrails.org"
|
32
23
|
# redirect_to "/images/screenshot.jpg"
|
33
|
-
# redirect_to
|
34
|
-
# redirect_to :back
|
24
|
+
# redirect_to posts_url
|
35
25
|
# redirect_to proc { edit_post_url(@post) }
|
36
26
|
#
|
37
|
-
# The redirection happens as a
|
27
|
+
# The redirection happens as a <tt>302 Found</tt> header unless otherwise specified using the <tt>:status</tt> option:
|
38
28
|
#
|
39
29
|
# redirect_to post_url(@post), status: :found
|
40
30
|
# redirect_to action: 'atom', status: :moved_permanently
|
41
31
|
# redirect_to post_url(@post), status: 301
|
42
32
|
# redirect_to action: 'atom', status: 302
|
43
33
|
#
|
44
|
-
# The status code can either be a standard {HTTP Status code}[
|
34
|
+
# The status code can either be a standard {HTTP Status code}[https://www.iana.org/assignments/http-status-codes] as an
|
45
35
|
# integer, or a symbol representing the downcased, underscored and symbolized description.
|
46
36
|
# Note that the status code must be a 3xx HTTP code, or redirection will not occur.
|
47
37
|
#
|
48
38
|
# If you are using XHR requests other than GET or POST and redirecting after the
|
49
39
|
# request then some browsers will follow the redirect using the original request
|
50
40
|
# method. This may lead to undesirable behavior such as a double DELETE. To work
|
51
|
-
# around this
|
41
|
+
# around this you can return a <tt>303 See Other</tt> status code which will be
|
52
42
|
# followed using a GET request.
|
53
43
|
#
|
54
44
|
# redirect_to posts_url, status: :see_other
|
@@ -62,18 +52,45 @@ module ActionController
|
|
62
52
|
# redirect_to post_url(@post), status: 301, flash: { updated_post_id: @post.id }
|
63
53
|
# redirect_to({ action: 'atom' }, alert: "Something serious happened")
|
64
54
|
#
|
65
|
-
#
|
66
|
-
#
|
67
|
-
#
|
68
|
-
|
69
|
-
def redirect_to(options = {}, response_status = {}) #:doc:
|
55
|
+
# Statements after +redirect_to+ in our controller get executed, so +redirect_to+ doesn't stop the execution of the function.
|
56
|
+
# To terminate the execution of the function immediately after the +redirect_to+, use return.
|
57
|
+
# redirect_to post_url(@post) and return
|
58
|
+
def redirect_to(options = {}, response_status = {})
|
70
59
|
raise ActionControllerError.new("Cannot redirect to nil!") unless options
|
71
|
-
raise ActionControllerError.new("Cannot redirect to a parameter hash!") if options.is_a?(ActionController::Parameters)
|
72
60
|
raise AbstractController::DoubleRenderError if response_body
|
73
61
|
|
74
62
|
self.status = _extract_redirect_to_status(options, response_status)
|
75
63
|
self.location = _compute_redirect_to_location(request, options)
|
76
|
-
self.response_body = "<html><body>You are being <a href=\"#{ERB::Util.unwrapped_html_escape(location)}\">redirected</a>.</body></html>"
|
64
|
+
self.response_body = "<html><body>You are being <a href=\"#{ERB::Util.unwrapped_html_escape(response.location)}\">redirected</a>.</body></html>"
|
65
|
+
end
|
66
|
+
|
67
|
+
# Redirects the browser to the page that issued the request (the referrer)
|
68
|
+
# if possible, otherwise redirects to the provided default fallback
|
69
|
+
# location.
|
70
|
+
#
|
71
|
+
# The referrer information is pulled from the HTTP +Referer+ (sic) header on
|
72
|
+
# the request. This is an optional header and its presence on the request is
|
73
|
+
# subject to browser security settings and user preferences. If the request
|
74
|
+
# is missing this header, the <tt>fallback_location</tt> will be used.
|
75
|
+
#
|
76
|
+
# redirect_back fallback_location: { action: "show", id: 5 }
|
77
|
+
# redirect_back fallback_location: @post
|
78
|
+
# redirect_back fallback_location: "http://www.rubyonrails.org"
|
79
|
+
# redirect_back fallback_location: "/images/screenshot.jpg"
|
80
|
+
# redirect_back fallback_location: posts_url
|
81
|
+
# redirect_back fallback_location: proc { edit_post_url(@post) }
|
82
|
+
# redirect_back fallback_location: '/', allow_other_host: false
|
83
|
+
#
|
84
|
+
# ==== Options
|
85
|
+
# * <tt>:fallback_location</tt> - The default fallback location that will be used on missing +Referer+ header.
|
86
|
+
# * <tt>:allow_other_host</tt> - Allow or disallow redirection to the host that is different to the current host, defaults to true.
|
87
|
+
#
|
88
|
+
# All other options that can be passed to <tt>redirect_to</tt> are accepted as
|
89
|
+
# options and the behavior is identical.
|
90
|
+
def redirect_back(fallback_location:, allow_other_host: true, **args)
|
91
|
+
referer = request.headers["Referer"]
|
92
|
+
redirect_to_referer = referer && (allow_other_host || _url_host_allowed?(referer))
|
93
|
+
redirect_to redirect_to_referer ? referer : fallback_location, **args
|
77
94
|
end
|
78
95
|
|
79
96
|
def _compute_redirect_to_location(request, options) #:nodoc:
|
@@ -81,16 +98,14 @@ module ActionController
|
|
81
98
|
# The scheme name consist of a letter followed by any combination of
|
82
99
|
# letters, digits, and the plus ("+"), period ("."), or hyphen ("-")
|
83
100
|
# characters; and is terminated by a colon (":").
|
84
|
-
# See
|
101
|
+
# See https://tools.ietf.org/html/rfc3986#section-3.1
|
85
102
|
# The protocol relative scheme starts with a double slash "//".
|
86
103
|
when /\A([a-z][a-z\d\-+\.]*:|\/\/).*/i
|
87
104
|
options
|
88
105
|
when String
|
89
106
|
request.protocol + request.host_with_port + options
|
90
|
-
when :back
|
91
|
-
request.headers["Referer"] or raise RedirectBackError
|
92
107
|
when Proc
|
93
|
-
_compute_redirect_to_location request, options
|
108
|
+
_compute_redirect_to_location request, instance_eval(&options)
|
94
109
|
else
|
95
110
|
url_for(options)
|
96
111
|
end.delete("\0\r\n")
|
@@ -108,5 +123,11 @@ module ActionController
|
|
108
123
|
302
|
109
124
|
end
|
110
125
|
end
|
126
|
+
|
127
|
+
def _url_host_allowed?(url)
|
128
|
+
URI(url.to_s).host == request.host
|
129
|
+
rescue ArgumentError, URI::Error
|
130
|
+
false
|
131
|
+
end
|
111
132
|
end
|
112
133
|
end
|
@@ -1,4 +1,6 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "set"
|
2
4
|
|
3
5
|
module ActionController
|
4
6
|
# See <tt>Renderers.add</tt>
|
@@ -11,6 +13,7 @@ module ActionController
|
|
11
13
|
Renderers.remove(key)
|
12
14
|
end
|
13
15
|
|
16
|
+
# See <tt>Responder#api_behavior</tt>
|
14
17
|
class MissingRenderer < LoadError
|
15
18
|
def initialize(format)
|
16
19
|
super "No renderer defined for format: #{format}"
|
@@ -20,40 +23,24 @@ module ActionController
|
|
20
23
|
module Renderers
|
21
24
|
extend ActiveSupport::Concern
|
22
25
|
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
end
|
26
|
+
# A Set containing renderer names that correspond to available renderer procs.
|
27
|
+
# Default values are <tt>:json</tt>, <tt>:js</tt>, <tt>:xml</tt>.
|
28
|
+
RENDERERS = Set.new
|
27
29
|
|
28
|
-
|
29
|
-
|
30
|
-
renderers = _renderers + args
|
31
|
-
self._renderers = renderers.freeze
|
32
|
-
end
|
33
|
-
alias use_renderer use_renderers
|
30
|
+
included do
|
31
|
+
class_attribute :_renderers, default: Set.new.freeze
|
34
32
|
end
|
35
33
|
|
36
|
-
|
37
|
-
|
38
|
-
|
34
|
+
# Used in <tt>ActionController::Base</tt>
|
35
|
+
# and <tt>ActionController::API</tt> to include all
|
36
|
+
# renderers by default.
|
37
|
+
module All
|
38
|
+
extend ActiveSupport::Concern
|
39
|
+
include Renderers
|
39
40
|
|
40
|
-
|
41
|
-
|
42
|
-
if options.key?(name)
|
43
|
-
_process_options(options)
|
44
|
-
method_name = Renderers._render_with_renderer_method_name(name)
|
45
|
-
return send(method_name, options.delete(name), options)
|
46
|
-
end
|
41
|
+
included do
|
42
|
+
self._renderers = RENDERERS
|
47
43
|
end
|
48
|
-
nil
|
49
|
-
end
|
50
|
-
|
51
|
-
# A Set containing renderer names that correspond to available renderer procs.
|
52
|
-
# Default values are <tt>:json</tt>, <tt>:js</tt>, <tt>:xml</tt>.
|
53
|
-
RENDERERS = Set.new
|
54
|
-
|
55
|
-
def self._render_with_renderer_method_name(key)
|
56
|
-
"_render_with_renderer_#{key}"
|
57
44
|
end
|
58
45
|
|
59
46
|
# Adds a new renderer to call within controller actions.
|
@@ -68,11 +55,11 @@ module ActionController
|
|
68
55
|
# ActionController::Renderers.add :csv do |obj, options|
|
69
56
|
# filename = options[:filename] || 'data'
|
70
57
|
# str = obj.respond_to?(:to_csv) ? obj.to_csv : obj.to_s
|
71
|
-
# send_data str, type: Mime
|
58
|
+
# send_data str, type: Mime[:csv],
|
72
59
|
# disposition: "attachment; filename=#{filename}.csv"
|
73
60
|
# end
|
74
61
|
#
|
75
|
-
# Note that we used Mime
|
62
|
+
# Note that we used Mime[:csv] for the csv mime type as it comes with Rails.
|
76
63
|
# For a custom renderer, you'll need to register a mime type with
|
77
64
|
# <tt>Mime::Type.register</tt>.
|
78
65
|
#
|
@@ -92,46 +79,102 @@ module ActionController
|
|
92
79
|
|
93
80
|
# This method is the opposite of add method.
|
94
81
|
#
|
95
|
-
#
|
82
|
+
# To remove a csv renderer:
|
96
83
|
#
|
97
84
|
# ActionController::Renderers.remove(:csv)
|
98
85
|
def self.remove(key)
|
99
86
|
RENDERERS.delete(key.to_sym)
|
100
87
|
method_name = _render_with_renderer_method_name(key)
|
101
|
-
|
88
|
+
remove_possible_method(method_name)
|
102
89
|
end
|
103
90
|
|
104
|
-
|
105
|
-
|
106
|
-
|
91
|
+
def self._render_with_renderer_method_name(key)
|
92
|
+
"_render_with_renderer_#{key}"
|
93
|
+
end
|
107
94
|
|
108
|
-
|
109
|
-
|
95
|
+
module ClassMethods
|
96
|
+
# Adds, by name, a renderer or renderers to the +_renderers+ available
|
97
|
+
# to call within controller actions.
|
98
|
+
#
|
99
|
+
# It is useful when rendering from an <tt>ActionController::Metal</tt> controller or
|
100
|
+
# otherwise to add an available renderer proc to a specific controller.
|
101
|
+
#
|
102
|
+
# Both <tt>ActionController::Base</tt> and <tt>ActionController::API</tt>
|
103
|
+
# include <tt>ActionController::Renderers::All</tt>, making all renderers
|
104
|
+
# available in the controller. See <tt>Renderers::RENDERERS</tt> and <tt>Renderers.add</tt>.
|
105
|
+
#
|
106
|
+
# Since <tt>ActionController::Metal</tt> controllers cannot render, the controller
|
107
|
+
# must include <tt>AbstractController::Rendering</tt>, <tt>ActionController::Rendering</tt>,
|
108
|
+
# and <tt>ActionController::Renderers</tt>, and have at least one renderer.
|
109
|
+
#
|
110
|
+
# Rather than including <tt>ActionController::Renderers::All</tt> and including all renderers,
|
111
|
+
# you may specify which renderers to include by passing the renderer name or names to
|
112
|
+
# +use_renderers+. For example, a controller that includes only the <tt>:json</tt> renderer
|
113
|
+
# (+_render_with_renderer_json+) might look like:
|
114
|
+
#
|
115
|
+
# class MetalRenderingController < ActionController::Metal
|
116
|
+
# include AbstractController::Rendering
|
117
|
+
# include ActionController::Rendering
|
118
|
+
# include ActionController::Renderers
|
119
|
+
#
|
120
|
+
# use_renderers :json
|
121
|
+
#
|
122
|
+
# def show
|
123
|
+
# render json: record
|
124
|
+
# end
|
125
|
+
# end
|
126
|
+
#
|
127
|
+
# You must specify a +use_renderer+, else the +controller.renderer+ and
|
128
|
+
# +controller._renderers+ will be <tt>nil</tt>, and the action will fail.
|
129
|
+
def use_renderers(*args)
|
130
|
+
renderers = _renderers + args
|
131
|
+
self._renderers = renderers.freeze
|
110
132
|
end
|
133
|
+
alias use_renderer use_renderers
|
134
|
+
end
|
135
|
+
|
136
|
+
# Called by +render+ in <tt>AbstractController::Rendering</tt>
|
137
|
+
# which sets the return value as the +response_body+.
|
138
|
+
#
|
139
|
+
# If no renderer is found, +super+ returns control to
|
140
|
+
# <tt>ActionView::Rendering.render_to_body</tt>, if present.
|
141
|
+
def render_to_body(options)
|
142
|
+
_render_to_body_with_renderer(options) || super
|
143
|
+
end
|
144
|
+
|
145
|
+
def _render_to_body_with_renderer(options)
|
146
|
+
_renderers.each do |name|
|
147
|
+
if options.key?(name)
|
148
|
+
_process_options(options)
|
149
|
+
method_name = Renderers._render_with_renderer_method_name(name)
|
150
|
+
return send(method_name, options.delete(name), options)
|
151
|
+
end
|
152
|
+
end
|
153
|
+
nil
|
111
154
|
end
|
112
155
|
|
113
156
|
add :json do |json, options|
|
114
157
|
json = json.to_json(options) unless json.kind_of?(String)
|
115
158
|
|
116
159
|
if options[:callback].present?
|
117
|
-
if content_type.nil? || content_type == Mime
|
118
|
-
self.content_type = Mime
|
160
|
+
if content_type.nil? || content_type == Mime[:json]
|
161
|
+
self.content_type = Mime[:js]
|
119
162
|
end
|
120
163
|
|
121
164
|
"/**/#{options[:callback]}(#{json})"
|
122
165
|
else
|
123
|
-
self.content_type ||= Mime
|
166
|
+
self.content_type ||= Mime[:json]
|
124
167
|
json
|
125
168
|
end
|
126
169
|
end
|
127
170
|
|
128
171
|
add :js do |js, options|
|
129
|
-
self.content_type ||= Mime
|
172
|
+
self.content_type ||= Mime[:js]
|
130
173
|
js.respond_to?(:to_js) ? js.to_js(options) : js
|
131
174
|
end
|
132
175
|
|
133
176
|
add :xml do |xml, options|
|
134
|
-
self.content_type ||= Mime
|
177
|
+
self.content_type ||= Mime[:xml]
|
135
178
|
xml.respond_to?(:to_xml) ? xml.to_xml(options) : xml
|
136
179
|
end
|
137
180
|
end
|