actionpack 4.2.10 → 5.0.0

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 (131) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +553 -401
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +2 -3
  5. data/lib/abstract_controller/base.rb +28 -38
  6. data/lib/{action_controller → abstract_controller}/caching/fragments.rb +51 -11
  7. data/lib/abstract_controller/caching.rb +62 -0
  8. data/lib/abstract_controller/callbacks.rb +52 -19
  9. data/lib/abstract_controller/collector.rb +4 -9
  10. data/lib/abstract_controller/error.rb +4 -0
  11. data/lib/abstract_controller/helpers.rb +4 -3
  12. data/lib/abstract_controller/railties/routes_helpers.rb +2 -2
  13. data/lib/abstract_controller/rendering.rb +28 -18
  14. data/lib/abstract_controller/translation.rb +8 -7
  15. data/lib/abstract_controller.rb +6 -2
  16. data/lib/action_controller/api/api_rendering.rb +14 -0
  17. data/lib/action_controller/api.rb +147 -0
  18. data/lib/action_controller/base.rb +10 -13
  19. data/lib/action_controller/caching.rb +13 -58
  20. data/lib/action_controller/form_builder.rb +48 -0
  21. data/lib/action_controller/log_subscriber.rb +3 -10
  22. data/lib/action_controller/metal/basic_implicit_render.rb +11 -0
  23. data/lib/action_controller/metal/conditional_get.rb +106 -34
  24. data/lib/action_controller/metal/cookies.rb +1 -3
  25. data/lib/action_controller/metal/data_streaming.rb +11 -32
  26. data/lib/action_controller/metal/etag_with_template_digest.rb +1 -1
  27. data/lib/action_controller/metal/exceptions.rb +11 -6
  28. data/lib/action_controller/metal/force_ssl.rb +10 -10
  29. data/lib/action_controller/metal/head.rb +14 -8
  30. data/lib/action_controller/metal/helpers.rb +15 -6
  31. data/lib/action_controller/metal/http_authentication.rb +44 -35
  32. data/lib/action_controller/metal/implicit_render.rb +61 -6
  33. data/lib/action_controller/metal/instrumentation.rb +5 -5
  34. data/lib/action_controller/metal/live.rb +66 -88
  35. data/lib/action_controller/metal/mime_responds.rb +27 -42
  36. data/lib/action_controller/metal/params_wrapper.rb +8 -8
  37. data/lib/action_controller/metal/redirecting.rb +32 -9
  38. data/lib/action_controller/metal/renderers.rb +85 -40
  39. data/lib/action_controller/metal/rendering.rb +38 -6
  40. data/lib/action_controller/metal/request_forgery_protection.rb +126 -48
  41. data/lib/action_controller/metal/rescue.rb +3 -12
  42. data/lib/action_controller/metal/streaming.rb +4 -4
  43. data/lib/action_controller/metal/strong_parameters.rb +293 -90
  44. data/lib/action_controller/metal/testing.rb +1 -12
  45. data/lib/action_controller/metal/url_for.rb +12 -5
  46. data/lib/action_controller/metal.rb +88 -63
  47. data/lib/action_controller/renderer.rb +111 -0
  48. data/lib/action_controller/template_assertions.rb +9 -0
  49. data/lib/action_controller/test_case.rb +288 -368
  50. data/lib/action_controller.rb +12 -9
  51. data/lib/action_dispatch/http/cache.rb +73 -34
  52. data/lib/action_dispatch/http/filter_parameters.rb +15 -11
  53. data/lib/action_dispatch/http/filter_redirect.rb +7 -8
  54. data/lib/action_dispatch/http/headers.rb +44 -13
  55. data/lib/action_dispatch/http/mime_negotiation.rb +41 -23
  56. data/lib/action_dispatch/http/mime_type.rb +126 -90
  57. data/lib/action_dispatch/http/mime_types.rb +3 -4
  58. data/lib/action_dispatch/http/parameter_filter.rb +18 -8
  59. data/lib/action_dispatch/http/parameters.rb +54 -41
  60. data/lib/action_dispatch/http/request.rb +149 -82
  61. data/lib/action_dispatch/http/response.rb +206 -102
  62. data/lib/action_dispatch/http/url.rb +117 -8
  63. data/lib/action_dispatch/journey/formatter.rb +39 -28
  64. data/lib/action_dispatch/journey/gtg/transition_table.rb +1 -1
  65. data/lib/action_dispatch/journey/nfa/dot.rb +0 -2
  66. data/lib/action_dispatch/journey/nfa/transition_table.rb +1 -46
  67. data/lib/action_dispatch/journey/nodes/node.rb +14 -4
  68. data/lib/action_dispatch/journey/parser_extras.rb +4 -0
  69. data/lib/action_dispatch/journey/path/pattern.rb +38 -42
  70. data/lib/action_dispatch/journey/route.rb +74 -19
  71. data/lib/action_dispatch/journey/router/utils.rb +5 -5
  72. data/lib/action_dispatch/journey/router.rb +5 -9
  73. data/lib/action_dispatch/journey/routes.rb +14 -15
  74. data/lib/action_dispatch/journey/visitors.rb +86 -43
  75. data/lib/action_dispatch/middleware/callbacks.rb +10 -1
  76. data/lib/action_dispatch/middleware/cookies.rb +189 -135
  77. data/lib/action_dispatch/middleware/debug_exceptions.rb +124 -49
  78. data/lib/action_dispatch/middleware/exception_wrapper.rb +21 -21
  79. data/lib/action_dispatch/middleware/executor.rb +19 -0
  80. data/lib/action_dispatch/middleware/flash.rb +66 -45
  81. data/lib/action_dispatch/middleware/params_parser.rb +32 -46
  82. data/lib/action_dispatch/middleware/public_exceptions.rb +2 -2
  83. data/lib/action_dispatch/middleware/reloader.rb +14 -58
  84. data/lib/action_dispatch/middleware/remote_ip.rb +29 -19
  85. data/lib/action_dispatch/middleware/request_id.rb +11 -6
  86. data/lib/action_dispatch/middleware/session/abstract_store.rb +23 -11
  87. data/lib/action_dispatch/middleware/session/cache_store.rb +9 -6
  88. data/lib/action_dispatch/middleware/session/cookie_store.rb +30 -24
  89. data/lib/action_dispatch/middleware/session/mem_cache_store.rb +4 -0
  90. data/lib/action_dispatch/middleware/show_exceptions.rb +11 -9
  91. data/lib/action_dispatch/middleware/ssl.rb +115 -36
  92. data/lib/action_dispatch/middleware/stack.rb +44 -40
  93. data/lib/action_dispatch/middleware/static.rb +51 -35
  94. data/lib/action_dispatch/middleware/templates/rescues/_request_and_response.html.erb +2 -14
  95. data/lib/action_dispatch/middleware/templates/rescues/_source.text.erb +8 -0
  96. data/lib/action_dispatch/middleware/templates/rescues/template_error.html.erb +1 -1
  97. data/lib/action_dispatch/middleware/templates/rescues/template_error.text.erb +1 -1
  98. data/lib/action_dispatch/middleware/templates/routes/_route.html.erb +4 -4
  99. data/lib/action_dispatch/middleware/templates/routes/_table.html.erb +59 -63
  100. data/lib/action_dispatch/railtie.rb +2 -2
  101. data/lib/action_dispatch/request/session.rb +69 -33
  102. data/lib/action_dispatch/request/utils.rb +51 -19
  103. data/lib/action_dispatch/routing/inspector.rb +32 -43
  104. data/lib/action_dispatch/routing/mapper.rb +491 -338
  105. data/lib/action_dispatch/routing/polymorphic_routes.rb +8 -14
  106. data/lib/action_dispatch/routing/redirection.rb +3 -3
  107. data/lib/action_dispatch/routing/route_set.rb +145 -238
  108. data/lib/action_dispatch/routing/url_for.rb +27 -10
  109. data/lib/action_dispatch/routing.rb +17 -13
  110. data/lib/action_dispatch/testing/assertion_response.rb +45 -0
  111. data/lib/action_dispatch/testing/assertions/response.rb +38 -20
  112. data/lib/action_dispatch/testing/assertions/routing.rb +11 -10
  113. data/lib/action_dispatch/testing/assertions.rb +1 -1
  114. data/lib/action_dispatch/testing/integration.rb +368 -97
  115. data/lib/action_dispatch/testing/test_process.rb +5 -6
  116. data/lib/action_dispatch/testing/test_request.rb +22 -31
  117. data/lib/action_dispatch/testing/test_response.rb +7 -4
  118. data/lib/action_dispatch.rb +3 -1
  119. data/lib/action_pack/gem_version.rb +3 -3
  120. data/lib/action_pack.rb +1 -1
  121. metadata +30 -34
  122. data/lib/action_controller/metal/hide_actions.rb +0 -40
  123. data/lib/action_controller/metal/rack_delegation.rb +0 -32
  124. data/lib/action_controller/middleware.rb +0 -39
  125. data/lib/action_controller/model_naming.rb +0 -12
  126. data/lib/action_dispatch/journey/backwards.rb +0 -5
  127. data/lib/action_dispatch/journey/router/strexp.rb +0 -27
  128. data/lib/action_dispatch/testing/assertions/dom.rb +0 -3
  129. data/lib/action_dispatch/testing/assertions/selector.rb +0 -3
  130. data/lib/action_dispatch/testing/assertions/tag.rb +0 -3
  131. /data/lib/action_dispatch/middleware/templates/rescues/{_source.erb → _source.html.erb} +0 -0
@@ -3,7 +3,7 @@ require 'delegate'
3
3
  require 'active_support/json'
4
4
 
5
5
  module ActionController
6
- # Mix this module in to your controller, and all actions in that controller
6
+ # Mix this module into your controller, and all actions in that controller
7
7
  # will be able to stream data to the client as it's written.
8
8
  #
9
9
  # class MyController < ActionController::Base
@@ -20,7 +20,7 @@ module ActionController
20
20
  # end
21
21
  # end
22
22
  #
23
- # There are a few caveats with this use. You *cannot* write headers after the
23
+ # There are a few caveats with this module. You *cannot* write headers after the
24
24
  # response has been committed (Response#committed? will return truthy).
25
25
  # Calling +write+ or +close+ on the response stream will cause the response
26
26
  # object to be committed. Make sure all headers are set before calling write
@@ -33,6 +33,20 @@ module ActionController
33
33
  # the main thread. Make sure your actions are thread safe, and this shouldn't
34
34
  # be a problem (don't share state across threads, etc).
35
35
  module Live
36
+ extend ActiveSupport::Concern
37
+
38
+ module ClassMethods
39
+ def make_response!(request)
40
+ if request.get_header("HTTP_VERSION") == "HTTP/1.0"
41
+ super
42
+ else
43
+ Live::Response.new.tap do |res|
44
+ res.request = request
45
+ end
46
+ end
47
+ end
48
+ end
49
+
36
50
  # This class provides the ability to write an SSE (Server Sent Event)
37
51
  # to an IO stream. The class is initialized with a stream and can be used
38
52
  # to either write a JSON string or an object which can be converted to JSON.
@@ -102,7 +116,7 @@ module ActionController
102
116
  end
103
117
  end
104
118
 
105
- message = json.gsub(/\n/, "\ndata: ")
119
+ message = json.gsub("\n".freeze, "\ndata: ".freeze)
106
120
  @stream.write "data: #{message}\n\n"
107
121
  end
108
122
  end
@@ -131,8 +145,8 @@ module ActionController
131
145
 
132
146
  def write(string)
133
147
  unless @response.committed?
134
- @response.headers["Cache-Control"] = "no-cache"
135
- @response.headers.delete "Content-Length"
148
+ @response.set_header "Cache-Control", "no-cache"
149
+ @response.delete_header "Content-Length"
136
150
  end
137
151
 
138
152
  super
@@ -149,14 +163,6 @@ module ActionController
149
163
  end
150
164
  end
151
165
 
152
- def each
153
- @response.sending!
154
- while str = @buf.pop
155
- yield str
156
- end
157
- @response.sent!
158
- end
159
-
160
166
  # Write a 'close' event to the buffer; the producer/writing thread
161
167
  # uses this to notify us that it's finished supplying content.
162
168
  #
@@ -189,12 +195,6 @@ module ActionController
189
195
  !@aborted
190
196
  end
191
197
 
192
- def await_close
193
- synchronize do
194
- @cv.wait_until { @closed }
195
- end
196
- end
197
-
198
198
  def on_error(&block)
199
199
  @error_callback = block
200
200
  end
@@ -202,32 +202,17 @@ module ActionController
202
202
  def call_on_error
203
203
  @error_callback.call
204
204
  end
205
- end
206
205
 
207
- class Response < ActionDispatch::Response #:nodoc: all
208
- class Header < DelegateClass(Hash) # :nodoc:
209
- def initialize(response, header)
210
- @response = response
211
- super(header)
212
- end
206
+ private
213
207
 
214
- def []=(k,v)
215
- if @response.committed?
216
- raise ActionDispatch::IllegalStateError, 'header already sent'
208
+ def each_chunk(&block)
209
+ while str = @buf.pop
210
+ yield str
217
211
  end
218
-
219
- super
220
- end
221
-
222
- def merge(other)
223
- self.class.new @response, __getobj__.merge(other)
224
212
  end
213
+ end
225
214
 
226
- def to_hash
227
- __getobj__.dup
228
- end
229
- end
230
-
215
+ class Response < ActionDispatch::Response #:nodoc: all
231
216
  private
232
217
 
233
218
  def before_committed
@@ -237,25 +222,11 @@ module ActionController
237
222
  jar.write self unless committed?
238
223
  end
239
224
 
240
- def before_sending
241
- super
242
- request.cookie_jar.commit!
243
- headers.freeze
244
- end
245
-
246
225
  def build_buffer(response, body)
247
226
  buf = Live::Buffer.new response
248
227
  body.each { |part| buf.write part }
249
228
  buf
250
229
  end
251
-
252
- def merge_default_headers(original, default)
253
- Header.new self, super
254
- end
255
-
256
- def handle_conditional_get!
257
- super unless committed?
258
- end
259
230
  end
260
231
 
261
232
  def process(name)
@@ -266,39 +237,55 @@ module ActionController
266
237
  # This processes the action in a child thread. It lets us return the
267
238
  # response code and headers back up the rack stack, and still process
268
239
  # the body in parallel with sending data to the client
269
- Thread.new {
270
- t2 = Thread.current
271
- t2.abort_on_exception = true
272
-
273
- # Since we're processing the view in a different thread, copy the
274
- # thread locals from the main thread to the child thread. :'(
275
- locals.each { |k,v| t2[k] = v }
276
-
277
- begin
278
- super(name)
279
- rescue => e
280
- if @_response.committed?
281
- begin
282
- @_response.stream.write(ActionView::Base.streaming_completion_on_exception) if request.format == :html
283
- @_response.stream.call_on_error
284
- rescue => exception
285
- log_error(exception)
286
- ensure
287
- log_error(e)
288
- @_response.stream.close
240
+ new_controller_thread {
241
+ ActiveSupport::Dependencies.interlock.running do
242
+ t2 = Thread.current
243
+
244
+ # Since we're processing the view in a different thread, copy the
245
+ # thread locals from the main thread to the child thread. :'(
246
+ locals.each { |k,v| t2[k] = v }
247
+
248
+ begin
249
+ super(name)
250
+ rescue => e
251
+ if @_response.committed?
252
+ begin
253
+ @_response.stream.write(ActionView::Base.streaming_completion_on_exception) if request.format == :html
254
+ @_response.stream.call_on_error
255
+ rescue => exception
256
+ log_error(exception)
257
+ ensure
258
+ log_error(e)
259
+ @_response.stream.close
260
+ end
261
+ else
262
+ error = e
289
263
  end
290
- else
291
- error = e
264
+ ensure
265
+ @_response.commit!
292
266
  end
293
- ensure
294
- @_response.commit!
295
267
  end
296
268
  }
297
269
 
298
- @_response.await_commit
270
+ ActiveSupport::Dependencies.interlock.permit_concurrent_loads do
271
+ @_response.await_commit
272
+ end
273
+
299
274
  raise error if error
300
275
  end
301
276
 
277
+ # Spawn a new thread to serve up the controller in. This is to get
278
+ # around the fact that Rack isn't based around IOs and we need to use
279
+ # a thread to stream data from the response bodies. Nobody should call
280
+ # this method except in Rails internals. Seriously!
281
+ def new_controller_thread # :nodoc:
282
+ Thread.new {
283
+ t2 = Thread.current
284
+ t2.abort_on_exception = true
285
+ yield
286
+ }
287
+ end
288
+
302
289
  def log_error(exception)
303
290
  logger = ActionController::Base.logger
304
291
  return unless logger
@@ -315,14 +302,5 @@ module ActionController
315
302
  super
316
303
  response.close if response
317
304
  end
318
-
319
- def set_response!(request)
320
- if request.env["HTTP_VERSION"] == "HTTP/1.0"
321
- super
322
- else
323
- @_response = Live::Response.new
324
- @_response.request = request
325
- end
326
- end
327
305
  end
328
306
  end
@@ -2,28 +2,6 @@ require 'abstract_controller/collector'
2
2
 
3
3
  module ActionController #:nodoc:
4
4
  module MimeResponds
5
- extend ActiveSupport::Concern
6
-
7
- # :stopdoc:
8
- module ClassMethods
9
- def respond_to(*)
10
- raise NoMethodError, "The controller-level `respond_to' feature has " \
11
- "been extracted to the `responders` gem. Add it to your Gemfile to " \
12
- "continue using this feature:\n" \
13
- " gem 'responders', '~> 2.0'\n" \
14
- "Consult the Rails upgrade guide for details."
15
- end
16
- end
17
-
18
- def respond_with(*)
19
- raise NoMethodError, "The `respond_with' feature has been extracted " \
20
- "to the `responders` gem. Add it to your Gemfile to continue using " \
21
- "this feature:\n" \
22
- " gem 'responders', '~> 2.0'\n" \
23
- "Consult the Rails upgrade guide for details."
24
- end
25
- # :startdoc:
26
-
27
5
  # Without web-service support, an action which collects the data for displaying a list of people
28
6
  # might look something like this:
29
7
  #
@@ -31,6 +9,13 @@ module ActionController #:nodoc:
31
9
  # @people = Person.all
32
10
  # end
33
11
  #
12
+ # That action implicitly responds to all formats, but formats can also be whitelisted:
13
+ #
14
+ # def index
15
+ # @people = Person.all
16
+ # respond_to :html, :js
17
+ # end
18
+ #
34
19
  # Here's the same action, with web-service support baked in:
35
20
  #
36
21
  # def index
@@ -38,11 +23,12 @@ module ActionController #:nodoc:
38
23
  #
39
24
  # respond_to do |format|
40
25
  # format.html
26
+ # format.js
41
27
  # format.xml { render xml: @people }
42
28
  # end
43
29
  # end
44
30
  #
45
- # What that says is, "if the client wants HTML in response to this action, just respond as we
31
+ # What that says is, "if the client wants HTML or JS in response to this action, just respond as we
46
32
  # would have before, but if the client wants XML, return them the list of people in XML format."
47
33
  # (Rails determines the desired response format from the HTTP Accept header submitted by the client.)
48
34
  #
@@ -113,11 +99,11 @@ module ActionController #:nodoc:
113
99
  # and accept Rails' defaults, life will be much easier.
114
100
  #
115
101
  # If you need to use a MIME type which isn't supported by default, you can register your own handlers in
116
- # config/initializers/mime_types.rb as follows.
102
+ # +config/initializers/mime_types.rb+ as follows.
117
103
  #
118
104
  # Mime::Type.register "image/jpg", :jpg
119
105
  #
120
- # Respond to also allows you to specify a common block for different formats by using any:
106
+ # Respond to also allows you to specify a common block for different formats by using +any+:
121
107
  #
122
108
  # def index
123
109
  # @people = Person.all
@@ -173,21 +159,21 @@ module ActionController #:nodoc:
173
159
  # format.html.none { render "trash" }
174
160
  # end
175
161
  #
176
- # Variants also support common `any`/`all` block that formats have.
162
+ # Variants also support common +any+/+all+ block that formats have.
177
163
  #
178
164
  # It works for both inline:
179
165
  #
180
166
  # respond_to do |format|
181
- # format.html.any { render text: "any" }
182
- # format.html.phone { render text: "phone" }
167
+ # format.html.any { render html: "any" }
168
+ # format.html.phone { render html: "phone" }
183
169
  # end
184
170
  #
185
171
  # and block syntax:
186
172
  #
187
173
  # respond_to do |format|
188
174
  # format.html do |variant|
189
- # variant.any(:tablet, :phablet){ render text: "any" }
190
- # variant.phone { render text: "phone" }
175
+ # variant.any(:tablet, :phablet){ render html: "any" }
176
+ # variant.phone { render html: "phone" }
191
177
  # end
192
178
  # end
193
179
  #
@@ -196,15 +182,12 @@ module ActionController #:nodoc:
196
182
  # request.variant = [:tablet, :phone]
197
183
  #
198
184
  # which will work similarly to formats and MIME types negotiation. If there will be no
199
- # :tablet variant declared, :phone variant will be picked:
185
+ # +:tablet+ variant declared, +:phone+ variant will be picked:
200
186
  #
201
187
  # respond_to do |format|
202
188
  # format.html.none
203
189
  # format.html.phone # this gets rendered
204
190
  # end
205
- #
206
- # Be sure to check the documentation of <tt>ActionController::MimeResponds.respond_to</tt>
207
- # for more examples.
208
191
  def respond_to(*mimes)
209
192
  raise ArgumentError, "respond_to takes either types or a block, never both" if mimes.any? && block_given?
210
193
 
@@ -213,8 +196,9 @@ module ActionController #:nodoc:
213
196
 
214
197
  if format = collector.negotiate_format(request)
215
198
  _process_format(format)
199
+ _set_rendered_content_type format
216
200
  response = collector.response
217
- response ? response.call : render({})
201
+ response.call if response
218
202
  else
219
203
  raise ActionController::UnknownFormat
220
204
  end
@@ -250,7 +234,7 @@ module ActionController #:nodoc:
250
234
  @responses = {}
251
235
  @variant = variant
252
236
 
253
- mimes.each { |mime| @responses["Mime::#{mime.upcase}".constantize] = nil }
237
+ mimes.each { |mime| @responses[Mime[mime]] = nil }
254
238
  end
255
239
 
256
240
  def any(*args, &block)
@@ -310,16 +294,17 @@ module ActionController #:nodoc:
310
294
  end
311
295
 
312
296
  def variant
313
- if @variant.nil?
297
+ if @variant.empty?
314
298
  @variants[:none] || @variants[:any]
315
- elsif (@variants.keys & @variant).any?
316
- @variant.each do |v|
317
- return @variants[v] if @variants.key?(v)
318
- end
319
299
  else
320
- @variants[:any]
300
+ @variants[variant_key]
321
301
  end
322
302
  end
303
+
304
+ private
305
+ def variant_key
306
+ @variant.find { |variant| @variants.key?(variant) } || :any
307
+ end
323
308
  end
324
309
  end
325
310
  end
@@ -1,7 +1,6 @@
1
1
  require 'active_support/core_ext/hash/slice'
2
2
  require 'active_support/core_ext/hash/except'
3
3
  require 'active_support/core_ext/module/anonymous'
4
- require 'active_support/core_ext/struct'
5
4
  require 'action_dispatch/http/mime_type'
6
5
 
7
6
  module ActionController
@@ -9,8 +8,7 @@ module ActionController
9
8
  # submit requests without having to specify any root elements.
10
9
  #
11
10
  # 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.
11
+ # and can be customized.
14
12
  #
15
13
  # You could also turn it on per controller by setting the format array to
16
14
  # a non-empty array:
@@ -42,7 +40,7 @@ module ActionController
42
40
  # wrap_parameters :person, include: [:username, :password]
43
41
  # end
44
42
  #
45
- # On ActiveRecord models with no +:include+ or +:exclude+ option set,
43
+ # On Active Record models with no +:include+ or +:exclude+ option set,
46
44
  # it will only wrap the parameters returned by the class method
47
45
  # <tt>attribute_names</tt>.
48
46
  #
@@ -86,7 +84,7 @@ module ActionController
86
84
  new name, format, include, exclude, nil, nil
87
85
  end
88
86
 
89
- def initialize(name, format, include, exclude, klass, model) # nodoc
87
+ def initialize(name, format, include, exclude, klass, model) # :nodoc:
90
88
  super
91
89
  @include_set = include
92
90
  @name_set = name
@@ -132,7 +130,7 @@ module ActionController
132
130
  private
133
131
  # Determine the wrapper model from the controller's name. By convention,
134
132
  # this could be done by trying to find the defined model that has the
135
- # same singularize name as the controller. For example, +UsersController+
133
+ # same singular name as the controller. For example, +UsersController+
136
134
  # will try to find if the +User+ model exists.
137
135
  #
138
136
  # This method also does namespace lookup. Foo::Bar::UsersController will
@@ -252,7 +250,7 @@ module ActionController
252
250
 
253
251
  private
254
252
 
255
- # Returns the wrapper key which will be used to stored wrapped parameters.
253
+ # Returns the wrapper key which will be used to store wrapped parameters.
256
254
  def _wrapper_key
257
255
  _wrapper_options.name
258
256
  end
@@ -278,7 +276,9 @@ module ActionController
278
276
 
279
277
  # Checks if we should perform parameters wrapping.
280
278
  def _wrapper_enabled?
281
- ref = request.content_mime_type.try(:ref)
279
+ return false unless request.has_content_type?
280
+
281
+ ref = request.content_mime_type.ref
282
282
  _wrapper_formats.include?(ref) && _wrapper_key && !request.request_parameters[_wrapper_key]
283
283
  end
284
284
  end
@@ -11,7 +11,6 @@ module ActionController
11
11
  extend ActiveSupport::Concern
12
12
 
13
13
  include AbstractController::Logger
14
- include ActionController::RackDelegation
15
14
  include ActionController::UrlFor
16
15
 
17
16
  # Redirects the browser to the target specified in +options+. This parameter can be any one of:
@@ -21,8 +20,6 @@ module ActionController
21
20
  # * <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
21
  # * <tt>String</tt> not containing a protocol - The current protocol and host is prepended to the string.
23
22
  # * <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
23
  #
27
24
  # === Examples:
28
25
  #
@@ -31,7 +28,6 @@ module ActionController
31
28
  # redirect_to "http://www.rubyonrails.org"
32
29
  # redirect_to "/images/screenshot.jpg"
33
30
  # redirect_to articles_url
34
- # redirect_to :back
35
31
  # redirect_to proc { edit_post_url(@post) }
36
32
  #
37
33
  # The redirection happens as a "302 Found" header unless otherwise specified using the <tt>:status</tt> option:
@@ -62,13 +58,8 @@ module ActionController
62
58
  # redirect_to post_url(@post), status: 301, flash: { updated_post_id: @post.id }
63
59
  # redirect_to({ action: 'atom' }, alert: "Something serious happened")
64
60
  #
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
61
  def redirect_to(options = {}, response_status = {}) #:doc:
70
62
  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
63
  raise AbstractController::DoubleRenderError if response_body
73
64
 
74
65
  self.status = _extract_redirect_to_status(options, response_status)
@@ -76,6 +67,32 @@ module ActionController
76
67
  self.response_body = "<html><body>You are being <a href=\"#{ERB::Util.unwrapped_html_escape(location)}\">redirected</a>.</body></html>"
77
68
  end
78
69
 
70
+ # Redirects the browser to the page that issued the request (the referrer)
71
+ # if possible, otherwise redirects to the provided default fallback
72
+ # location.
73
+ #
74
+ # The referrer information is pulled from the HTTP `Referer` (sic) header on
75
+ # the request. This is an optional header and its presence on the request is
76
+ # subject to browser security settings and user preferences. If the request
77
+ # is missing this header, the <tt>fallback_location</tt> will be used.
78
+ #
79
+ # redirect_back fallback_location: { action: "show", id: 5 }
80
+ # redirect_back fallback_location: post
81
+ # redirect_back fallback_location: "http://www.rubyonrails.org"
82
+ # redirect_back fallback_location: "/images/screenshot.jpg"
83
+ # redirect_back fallback_location: articles_url
84
+ # redirect_back fallback_location: proc { edit_post_url(@post) }
85
+ #
86
+ # All options that can be passed to <tt>redirect_to</tt> are accepted as
87
+ # options and the behavior is identical.
88
+ def redirect_back(fallback_location:, **args)
89
+ if referer = request.headers["Referer"]
90
+ redirect_to referer, **args
91
+ else
92
+ redirect_to fallback_location, **args
93
+ end
94
+ end
95
+
79
96
  def _compute_redirect_to_location(request, options) #:nodoc:
80
97
  case options
81
98
  # The scheme name consist of a letter followed by any combination of
@@ -88,6 +105,12 @@ module ActionController
88
105
  when String
89
106
  request.protocol + request.host_with_port + options
90
107
  when :back
108
+ ActiveSupport::Deprecation.warn(<<-MESSAGE.squish)
109
+ `redirect_to :back` is deprecated and will be removed from Rails 5.1.
110
+ Please use `redirect_back(fallback_location: fallback_location)` where
111
+ `fallback_location` represents the location to use if the request has
112
+ no HTTP referer information.
113
+ MESSAGE
91
114
  request.headers["Referer"] or raise RedirectBackError
92
115
  when Proc
93
116
  _compute_redirect_to_location request, options.call