actionpack 4.2.11.1 → 5.2.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.

Files changed (166) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +328 -458
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +6 -7
  5. data/lib/abstract_controller/asset_paths.rb +2 -0
  6. data/lib/abstract_controller/base.rb +45 -49
  7. data/lib/{action_controller → abstract_controller}/caching/fragments.rb +78 -15
  8. data/lib/abstract_controller/caching.rb +66 -0
  9. data/lib/abstract_controller/callbacks.rb +47 -31
  10. data/lib/abstract_controller/collector.rb +8 -11
  11. data/lib/abstract_controller/error.rb +6 -0
  12. data/lib/abstract_controller/helpers.rb +25 -25
  13. data/lib/abstract_controller/logger.rb +2 -0
  14. data/lib/abstract_controller/railties/routes_helpers.rb +4 -2
  15. data/lib/abstract_controller/rendering.rb +42 -41
  16. data/lib/abstract_controller/translation.rb +10 -7
  17. data/lib/abstract_controller/url_for.rb +2 -0
  18. data/lib/abstract_controller.rb +12 -5
  19. data/lib/action_controller/api/api_rendering.rb +16 -0
  20. data/lib/action_controller/api.rb +149 -0
  21. data/lib/action_controller/base.rb +27 -19
  22. data/lib/action_controller/caching.rb +14 -57
  23. data/lib/action_controller/form_builder.rb +50 -0
  24. data/lib/action_controller/log_subscriber.rb +10 -15
  25. data/lib/action_controller/metal/basic_implicit_render.rb +13 -0
  26. data/lib/action_controller/metal/conditional_get.rb +118 -44
  27. data/lib/action_controller/metal/content_security_policy.rb +52 -0
  28. data/lib/action_controller/metal/cookies.rb +3 -3
  29. data/lib/action_controller/metal/data_streaming.rb +27 -46
  30. data/lib/action_controller/metal/etag_with_flash.rb +18 -0
  31. data/lib/action_controller/metal/etag_with_template_digest.rb +20 -13
  32. data/lib/action_controller/metal/exceptions.rb +8 -14
  33. data/lib/action_controller/metal/flash.rb +4 -3
  34. data/lib/action_controller/metal/force_ssl.rb +23 -21
  35. data/lib/action_controller/metal/head.rb +21 -19
  36. data/lib/action_controller/metal/helpers.rb +24 -14
  37. data/lib/action_controller/metal/http_authentication.rb +65 -58
  38. data/lib/action_controller/metal/implicit_render.rb +62 -8
  39. data/lib/action_controller/metal/instrumentation.rb +19 -21
  40. data/lib/action_controller/metal/live.rb +90 -106
  41. data/lib/action_controller/metal/mime_responds.rb +33 -46
  42. data/lib/action_controller/metal/parameter_encoding.rb +51 -0
  43. data/lib/action_controller/metal/params_wrapper.rb +61 -53
  44. data/lib/action_controller/metal/redirecting.rb +49 -28
  45. data/lib/action_controller/metal/renderers.rb +87 -44
  46. data/lib/action_controller/metal/rendering.rb +72 -50
  47. data/lib/action_controller/metal/request_forgery_protection.rb +284 -97
  48. data/lib/action_controller/metal/rescue.rb +9 -16
  49. data/lib/action_controller/metal/streaming.rb +12 -10
  50. data/lib/action_controller/metal/strong_parameters.rb +583 -164
  51. data/lib/action_controller/metal/testing.rb +2 -17
  52. data/lib/action_controller/metal/url_for.rb +19 -10
  53. data/lib/action_controller/metal.rb +98 -83
  54. data/lib/action_controller/railtie.rb +28 -10
  55. data/lib/action_controller/railties/helpers.rb +2 -0
  56. data/lib/action_controller/renderer.rb +117 -0
  57. data/lib/action_controller/template_assertions.rb +11 -0
  58. data/lib/action_controller/test_case.rb +282 -413
  59. data/lib/action_controller.rb +29 -21
  60. data/lib/action_dispatch/http/cache.rb +93 -47
  61. data/lib/action_dispatch/http/content_security_policy.rb +272 -0
  62. data/lib/action_dispatch/http/filter_parameters.rb +26 -20
  63. data/lib/action_dispatch/http/filter_redirect.rb +10 -11
  64. data/lib/action_dispatch/http/headers.rb +55 -22
  65. data/lib/action_dispatch/http/mime_negotiation.rb +56 -41
  66. data/lib/action_dispatch/http/mime_type.rb +134 -121
  67. data/lib/action_dispatch/http/mime_types.rb +20 -6
  68. data/lib/action_dispatch/http/parameter_filter.rb +25 -11
  69. data/lib/action_dispatch/http/parameters.rb +98 -39
  70. data/lib/action_dispatch/http/rack_cache.rb +2 -0
  71. data/lib/action_dispatch/http/request.rb +200 -118
  72. data/lib/action_dispatch/http/response.rb +225 -110
  73. data/lib/action_dispatch/http/upload.rb +12 -6
  74. data/lib/action_dispatch/http/url.rb +110 -28
  75. data/lib/action_dispatch/journey/formatter.rb +55 -32
  76. data/lib/action_dispatch/journey/gtg/builder.rb +7 -5
  77. data/lib/action_dispatch/journey/gtg/simulator.rb +3 -9
  78. data/lib/action_dispatch/journey/gtg/transition_table.rb +17 -16
  79. data/lib/action_dispatch/journey/nfa/builder.rb +5 -3
  80. data/lib/action_dispatch/journey/nfa/dot.rb +13 -13
  81. data/lib/action_dispatch/journey/nfa/simulator.rb +3 -1
  82. data/lib/action_dispatch/journey/nfa/transition_table.rb +5 -48
  83. data/lib/action_dispatch/journey/nodes/node.rb +18 -6
  84. data/lib/action_dispatch/journey/parser.rb +23 -22
  85. data/lib/action_dispatch/journey/parser.y +3 -2
  86. data/lib/action_dispatch/journey/parser_extras.rb +12 -4
  87. data/lib/action_dispatch/journey/path/pattern.rb +50 -44
  88. data/lib/action_dispatch/journey/route.rb +106 -28
  89. data/lib/action_dispatch/journey/router/utils.rb +20 -11
  90. data/lib/action_dispatch/journey/router.rb +35 -23
  91. data/lib/action_dispatch/journey/routes.rb +18 -16
  92. data/lib/action_dispatch/journey/scanner.rb +18 -15
  93. data/lib/action_dispatch/journey/visitors.rb +99 -52
  94. data/lib/action_dispatch/journey.rb +7 -5
  95. data/lib/action_dispatch/middleware/callbacks.rb +1 -2
  96. data/lib/action_dispatch/middleware/cookies.rb +304 -193
  97. data/lib/action_dispatch/middleware/debug_exceptions.rb +152 -57
  98. data/lib/action_dispatch/middleware/debug_locks.rb +124 -0
  99. data/lib/action_dispatch/middleware/exception_wrapper.rb +68 -69
  100. data/lib/action_dispatch/middleware/executor.rb +21 -0
  101. data/lib/action_dispatch/middleware/flash.rb +78 -54
  102. data/lib/action_dispatch/middleware/public_exceptions.rb +27 -25
  103. data/lib/action_dispatch/middleware/reloader.rb +5 -91
  104. data/lib/action_dispatch/middleware/remote_ip.rb +41 -31
  105. data/lib/action_dispatch/middleware/request_id.rb +17 -9
  106. data/lib/action_dispatch/middleware/session/abstract_store.rb +41 -25
  107. data/lib/action_dispatch/middleware/session/cache_store.rb +24 -14
  108. data/lib/action_dispatch/middleware/session/cookie_store.rb +72 -67
  109. data/lib/action_dispatch/middleware/session/mem_cache_store.rb +8 -2
  110. data/lib/action_dispatch/middleware/show_exceptions.rb +26 -22
  111. data/lib/action_dispatch/middleware/ssl.rb +114 -36
  112. data/lib/action_dispatch/middleware/stack.rb +31 -44
  113. data/lib/action_dispatch/middleware/static.rb +57 -50
  114. data/lib/action_dispatch/middleware/templates/rescues/_request_and_response.html.erb +2 -14
  115. data/lib/action_dispatch/middleware/templates/rescues/{_source.erb → _source.html.erb} +0 -0
  116. data/lib/action_dispatch/middleware/templates/rescues/_source.text.erb +8 -0
  117. data/lib/action_dispatch/middleware/templates/rescues/invalid_statement.html.erb +21 -0
  118. data/lib/action_dispatch/middleware/templates/rescues/invalid_statement.text.erb +13 -0
  119. data/lib/action_dispatch/middleware/templates/rescues/layout.erb +1 -0
  120. data/lib/action_dispatch/middleware/templates/rescues/template_error.html.erb +1 -1
  121. data/lib/action_dispatch/middleware/templates/rescues/template_error.text.erb +1 -1
  122. data/lib/action_dispatch/middleware/templates/routes/_route.html.erb +4 -4
  123. data/lib/action_dispatch/middleware/templates/routes/_table.html.erb +64 -64
  124. data/lib/action_dispatch/railtie.rb +19 -11
  125. data/lib/action_dispatch/request/session.rb +106 -59
  126. data/lib/action_dispatch/request/utils.rb +67 -24
  127. data/lib/action_dispatch/routing/endpoint.rb +9 -2
  128. data/lib/action_dispatch/routing/inspector.rb +58 -67
  129. data/lib/action_dispatch/routing/mapper.rb +733 -447
  130. data/lib/action_dispatch/routing/polymorphic_routes.rb +166 -140
  131. data/lib/action_dispatch/routing/redirection.rb +36 -26
  132. data/lib/action_dispatch/routing/route_set.rb +321 -291
  133. data/lib/action_dispatch/routing/routes_proxy.rb +32 -5
  134. data/lib/action_dispatch/routing/url_for.rb +65 -25
  135. data/lib/action_dispatch/routing.rb +17 -18
  136. data/lib/action_dispatch/system_test_case.rb +147 -0
  137. data/lib/action_dispatch/system_testing/browser.rb +49 -0
  138. data/lib/action_dispatch/system_testing/driver.rb +59 -0
  139. data/lib/action_dispatch/system_testing/server.rb +31 -0
  140. data/lib/action_dispatch/system_testing/test_helpers/screenshot_helper.rb +96 -0
  141. data/lib/action_dispatch/system_testing/test_helpers/setup_and_teardown.rb +31 -0
  142. data/lib/action_dispatch/system_testing/test_helpers/undef_methods.rb +26 -0
  143. data/lib/action_dispatch/testing/assertion_response.rb +47 -0
  144. data/lib/action_dispatch/testing/assertions/response.rb +45 -20
  145. data/lib/action_dispatch/testing/assertions/routing.rb +30 -26
  146. data/lib/action_dispatch/testing/assertions.rb +6 -4
  147. data/lib/action_dispatch/testing/integration.rb +348 -209
  148. data/lib/action_dispatch/testing/request_encoder.rb +55 -0
  149. data/lib/action_dispatch/testing/test_process.rb +28 -22
  150. data/lib/action_dispatch/testing/test_request.rb +27 -34
  151. data/lib/action_dispatch/testing/test_response.rb +35 -7
  152. data/lib/action_dispatch.rb +27 -19
  153. data/lib/action_pack/gem_version.rb +5 -3
  154. data/lib/action_pack/version.rb +3 -1
  155. data/lib/action_pack.rb +4 -2
  156. metadata +56 -38
  157. data/lib/action_controller/metal/hide_actions.rb +0 -40
  158. data/lib/action_controller/metal/rack_delegation.rb +0 -32
  159. data/lib/action_controller/middleware.rb +0 -39
  160. data/lib/action_controller/model_naming.rb +0 -12
  161. data/lib/action_dispatch/journey/backwards.rb +0 -5
  162. data/lib/action_dispatch/journey/router/strexp.rb +0 -27
  163. data/lib/action_dispatch/middleware/params_parser.rb +0 -60
  164. data/lib/action_dispatch/testing/assertions/dom.rb +0 -3
  165. data/lib/action_dispatch/testing/assertions/selector.rb +0 -3
  166. data/lib/action_dispatch/testing/assertions/tag.rb +0 -3
@@ -1,16 +1,16 @@
1
- require 'active_support/core_ext/hash/slice'
2
- require 'active_support/core_ext/hash/except'
3
- require 'active_support/core_ext/module/anonymous'
4
- require 'active_support/core_ext/struct'
5
- require 'action_dispatch/http/mime_type'
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. If you are upgrading to \Rails 3.1, this file will
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 ActiveRecord models with no +:include+ or +:exclude+ option set,
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 'mutex_m'
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 || synchronize { super || self.model = _default_wrap_model }
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
- self.include = m.attribute_names
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
- # Determine the wrapper model from the controller's name. By convention,
134
- # this could be done by trying to find the defined model that has the
135
- # same singularize name as the controller. For example, +UsersController+
136
- # will try to find if the +User+ model exists.
137
- #
138
- # This method also does namespace lookup. Foo::Bar::UsersController will
139
- # try to find Foo::Bar::User, Foo::User and finally User.
140
- def _default_wrap_model #:nodoc:
141
- return nil if klass.anonymous?
142
- model_name = klass.name.sub(/Controller$/, '').classify
143
-
144
- begin
145
- if model_klass = model_name.safe_constantize
146
- model_klass
147
- else
148
- namespaces = model_name.split("::")
149
- namespaces.delete_at(-2)
150
- break if namespaces.last == model_name
151
- model_name = namespaces.join("::")
152
- end
153
- end until model_klass
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
- model_klass
156
- end
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(:format => [])
214
+ options = options.merge(format: [])
204
215
  when Symbol, String
205
- options = options.merge(:name => name_or_model_or_options)
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 = Options.from_hash _wrapper_options.to_h.slice(:format).merge(options)
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. Will be called automatically when the
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. Will be called automatically
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
- if request.parameters[_wrapper_key].present?
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 stored wrapped parameters.
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
- ref = request.content_mime_type.try(:ref)
282
- _wrapper_formats.include?(ref) && _wrapper_key && !request.request_parameters[_wrapper_key]
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
- module ActionController
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 articles_url
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 "302 Found" header unless otherwise specified using the <tt>:status</tt> option:
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}[http://www.iana.org/assignments/http-status-codes] as an
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 you can return a <tt>303 See Other</tt> status code which will be
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
- # When using <tt>redirect_to :back</tt>, if there is no referrer,
66
- # <tt>ActionController::RedirectBackError</tt> will be raised. You
67
- # may specify some fallback behavior for this case by rescuing
68
- # <tt>ActionController::RedirectBackError</tt>.
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 http://tools.ietf.org/html/rfc3986#section-3.1
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.call
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
- require 'set'
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
- included do
24
- class_attribute :_renderers
25
- self._renderers = Set.new.freeze
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
- module ClassMethods
29
- def use_renderers(*args)
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
- def render_to_body(options)
37
- _render_to_body_with_renderer(options) || super
38
- end
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
- def _render_to_body_with_renderer(options)
41
- _renderers.each do |name|
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::CSV,
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::CSV for the csv mime type as it comes with Rails.
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
- # Usage:
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
- remove_method(method_name) if method_defined?(method_name)
88
+ remove_possible_method(method_name)
102
89
  end
103
90
 
104
- module All
105
- extend ActiveSupport::Concern
106
- include Renderers
91
+ def self._render_with_renderer_method_name(key)
92
+ "_render_with_renderer_#{key}"
93
+ end
107
94
 
108
- included do
109
- self._renderers = RENDERERS
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::JSON
118
- self.content_type = Mime::JS
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::JSON
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::JS
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::XML
177
+ self.content_type ||= Mime[:xml]
135
178
  xml.respond_to?(:to_xml) ? xml.to_xml(options) : xml
136
179
  end
137
180
  end