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,9 +1,11 @@
1
- require 'action_dispatch/http/response'
2
- require 'delegate'
3
- require 'active_support/json'
1
+ # frozen_string_literal: true
2
+
3
+ require "action_dispatch/http/response"
4
+ require "delegate"
5
+ require "active_support/json"
4
6
 
5
7
  module ActionController
6
- # Mix this module in to your controller, and all actions in that controller
8
+ # Mix this module into your controller, and all actions in that controller
7
9
  # will be able to stream data to the client as it's written.
8
10
  #
9
11
  # class MyController < ActionController::Base
@@ -20,7 +22,7 @@ module ActionController
20
22
  # end
21
23
  # end
22
24
  #
23
- # There are a few caveats with this use. You *cannot* write headers after the
25
+ # There are a few caveats with this module. You *cannot* write headers after the
24
26
  # response has been committed (Response#committed? will return truthy).
25
27
  # Calling +write+ or +close+ on the response stream will cause the response
26
28
  # object to be committed. Make sure all headers are set before calling write
@@ -33,6 +35,20 @@ module ActionController
33
35
  # the main thread. Make sure your actions are thread safe, and this shouldn't
34
36
  # be a problem (don't share state across threads, etc).
35
37
  module Live
38
+ extend ActiveSupport::Concern
39
+
40
+ module ClassMethods
41
+ def make_response!(request)
42
+ if request.get_header("HTTP_VERSION") == "HTTP/1.0"
43
+ super
44
+ else
45
+ Live::Response.new.tap do |res|
46
+ res.request = request
47
+ end
48
+ end
49
+ end
50
+ end
51
+
36
52
  # This class provides the ability to write an SSE (Server Sent Event)
37
53
  # to an IO stream. The class is initialized with a stream and can be used
38
54
  # to either write a JSON string or an object which can be converted to JSON.
@@ -70,7 +86,6 @@ module ActionController
70
86
  # Note: SSEs are not currently supported by IE. However, they are supported
71
87
  # by Chrome, Firefox, Opera, and Safari.
72
88
  class SSE
73
-
74
89
  WHITELISTED_OPTIONS = %w( retry event id )
75
90
 
76
91
  def initialize(stream, options = {})
@@ -102,7 +117,7 @@ module ActionController
102
117
  end
103
118
  end
104
119
 
105
- message = json.gsub(/\n/, "\ndata: ")
120
+ message = json.gsub("\n".freeze, "\ndata: ".freeze)
106
121
  @stream.write "data: #{message}\n\n"
107
122
  end
108
123
  end
@@ -131,8 +146,8 @@ module ActionController
131
146
 
132
147
  def write(string)
133
148
  unless @response.committed?
134
- @response.headers["Cache-Control"] = "no-cache"
135
- @response.headers.delete "Content-Length"
149
+ @response.set_header "Cache-Control", "no-cache"
150
+ @response.delete_header "Content-Length"
136
151
  end
137
152
 
138
153
  super
@@ -149,14 +164,6 @@ module ActionController
149
164
  end
150
165
  end
151
166
 
152
- def each
153
- @response.sending!
154
- while str = @buf.pop
155
- yield str
156
- end
157
- @response.sent!
158
- end
159
-
160
167
  # Write a 'close' event to the buffer; the producer/writing thread
161
168
  # uses this to notify us that it's finished supplying content.
162
169
  #
@@ -189,12 +196,6 @@ module ActionController
189
196
  !@aborted
190
197
  end
191
198
 
192
- def await_close
193
- synchronize do
194
- @cv.wait_until { @closed }
195
- end
196
- end
197
-
198
199
  def on_error(&block)
199
200
  @error_callback = block
200
201
  end
@@ -202,60 +203,36 @@ module ActionController
202
203
  def call_on_error
203
204
  @error_callback.call
204
205
  end
205
- end
206
206
 
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
207
+ private
213
208
 
214
- def []=(k,v)
215
- if @response.committed?
216
- raise ActionDispatch::IllegalStateError, 'header already sent'
209
+ def each_chunk(&block)
210
+ loop do
211
+ str = nil
212
+ ActiveSupport::Dependencies.interlock.permit_concurrent_loads do
213
+ str = @buf.pop
214
+ end
215
+ break unless str
216
+ yield str
217
217
  end
218
-
219
- super
220
- end
221
-
222
- def merge(other)
223
- self.class.new @response, __getobj__.merge(other)
224
218
  end
219
+ end
225
220
 
226
- def to_hash
227
- __getobj__.dup
228
- end
229
- end
230
-
221
+ class Response < ActionDispatch::Response #:nodoc: all
231
222
  private
232
223
 
233
- def before_committed
234
- super
235
- jar = request.cookie_jar
236
- # The response can be committed multiple times
237
- jar.write self unless committed?
238
- end
239
-
240
- def before_sending
241
- super
242
- request.cookie_jar.commit!
243
- headers.freeze
244
- end
245
-
246
- def build_buffer(response, body)
247
- buf = Live::Buffer.new response
248
- body.each { |part| buf.write part }
249
- buf
250
- end
251
-
252
- def merge_default_headers(original, default)
253
- Header.new self, super
254
- end
224
+ def before_committed
225
+ super
226
+ jar = request.cookie_jar
227
+ # The response can be committed multiple times
228
+ jar.write self unless committed?
229
+ end
255
230
 
256
- def handle_conditional_get!
257
- super unless committed?
258
- end
231
+ def build_buffer(response, body)
232
+ buf = Live::Buffer.new response
233
+ body.each { |part| buf.write part }
234
+ buf
235
+ end
259
236
  end
260
237
 
261
238
  def process(name)
@@ -264,47 +241,63 @@ module ActionController
264
241
 
265
242
  error = nil
266
243
  # This processes the action in a child thread. It lets us return the
267
- # response code and headers back up the rack stack, and still process
268
- # 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
244
+ # response code and headers back up the Rack stack, and still process
245
+ # the body in parallel with sending data to the client.
246
+ new_controller_thread {
247
+ ActiveSupport::Dependencies.interlock.running do
248
+ t2 = Thread.current
249
+
250
+ # Since we're processing the view in a different thread, copy the
251
+ # thread locals from the main thread to the child thread. :'(
252
+ locals.each { |k, v| t2[k] = v }
253
+
254
+ begin
255
+ super(name)
256
+ rescue => e
257
+ if @_response.committed?
258
+ begin
259
+ @_response.stream.write(ActionView::Base.streaming_completion_on_exception) if request.format == :html
260
+ @_response.stream.call_on_error
261
+ rescue => exception
262
+ log_error(exception)
263
+ ensure
264
+ log_error(e)
265
+ @_response.stream.close
266
+ end
267
+ else
268
+ error = e
289
269
  end
290
- else
291
- error = e
270
+ ensure
271
+ @_response.commit!
292
272
  end
293
- ensure
294
- @_response.commit!
295
273
  end
296
274
  }
297
275
 
298
- @_response.await_commit
276
+ ActiveSupport::Dependencies.interlock.permit_concurrent_loads do
277
+ @_response.await_commit
278
+ end
279
+
299
280
  raise error if error
300
281
  end
301
282
 
283
+ # Spawn a new thread to serve up the controller in. This is to get
284
+ # around the fact that Rack isn't based around IOs and we need to use
285
+ # a thread to stream data from the response bodies. Nobody should call
286
+ # this method except in Rails internals. Seriously!
287
+ def new_controller_thread # :nodoc:
288
+ Thread.new {
289
+ t2 = Thread.current
290
+ t2.abort_on_exception = true
291
+ yield
292
+ }
293
+ end
294
+
302
295
  def log_error(exception)
303
296
  logger = ActionController::Base.logger
304
297
  return unless logger
305
298
 
306
299
  logger.fatal do
307
- message = "\n#{exception.class} (#{exception.message}):\n"
300
+ message = "\n#{exception.class} (#{exception.message}):\n".dup
308
301
  message << exception.annoted_source_code.to_s if exception.respond_to?(:annoted_source_code)
309
302
  message << " " << exception.backtrace.join("\n ")
310
303
  "#{message}\n\n"
@@ -315,14 +308,5 @@ module ActionController
315
308
  super
316
309
  response.close if response
317
310
  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
311
  end
328
312
  end
@@ -1,29 +1,9 @@
1
- require 'abstract_controller/collector'
1
+ # frozen_string_literal: true
2
+
3
+ require "abstract_controller/collector"
2
4
 
3
5
  module ActionController #:nodoc:
4
6
  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
7
  # Without web-service support, an action which collects the data for displaying a list of people
28
8
  # might look something like this:
29
9
  #
@@ -31,6 +11,13 @@ module ActionController #:nodoc:
31
11
  # @people = Person.all
32
12
  # end
33
13
  #
14
+ # That action implicitly responds to all formats, but formats can also be whitelisted:
15
+ #
16
+ # def index
17
+ # @people = Person.all
18
+ # respond_to :html, :js
19
+ # end
20
+ #
34
21
  # Here's the same action, with web-service support baked in:
35
22
  #
36
23
  # def index
@@ -38,11 +25,12 @@ module ActionController #:nodoc:
38
25
  #
39
26
  # respond_to do |format|
40
27
  # format.html
28
+ # format.js
41
29
  # format.xml { render xml: @people }
42
30
  # end
43
31
  # end
44
32
  #
45
- # What that says is, "if the client wants HTML in response to this action, just respond as we
33
+ # What that says is, "if the client wants HTML or JS in response to this action, just respond as we
46
34
  # would have before, but if the client wants XML, return them the list of people in XML format."
47
35
  # (Rails determines the desired response format from the HTTP Accept header submitted by the client.)
48
36
  #
@@ -113,11 +101,11 @@ module ActionController #:nodoc:
113
101
  # and accept Rails' defaults, life will be much easier.
114
102
  #
115
103
  # 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.
104
+ # +config/initializers/mime_types.rb+ as follows.
117
105
  #
118
106
  # Mime::Type.register "image/jpg", :jpg
119
107
  #
120
- # Respond to also allows you to specify a common block for different formats by using any:
108
+ # Respond to also allows you to specify a common block for different formats by using +any+:
121
109
  #
122
110
  # def index
123
111
  # @people = Person.all
@@ -173,21 +161,21 @@ module ActionController #:nodoc:
173
161
  # format.html.none { render "trash" }
174
162
  # end
175
163
  #
176
- # Variants also support common `any`/`all` block that formats have.
164
+ # Variants also support common +any+/+all+ block that formats have.
177
165
  #
178
166
  # It works for both inline:
179
167
  #
180
168
  # respond_to do |format|
181
- # format.html.any { render text: "any" }
182
- # format.html.phone { render text: "phone" }
169
+ # format.html.any { render html: "any" }
170
+ # format.html.phone { render html: "phone" }
183
171
  # end
184
172
  #
185
173
  # and block syntax:
186
174
  #
187
175
  # respond_to do |format|
188
176
  # format.html do |variant|
189
- # variant.any(:tablet, :phablet){ render text: "any" }
190
- # variant.phone { render text: "phone" }
177
+ # variant.any(:tablet, :phablet){ render html: "any" }
178
+ # variant.phone { render html: "phone" }
191
179
  # end
192
180
  # end
193
181
  #
@@ -195,16 +183,13 @@ module ActionController #:nodoc:
195
183
  #
196
184
  # request.variant = [:tablet, :phone]
197
185
  #
198
- # which will work similarly to formats and MIME types negotiation. If there will be no
199
- # :tablet variant declared, :phone variant will be picked:
186
+ # This will work similarly to formats and MIME types negotiation. If there
187
+ # is no +:tablet+ variant declared, the +:phone+ variant will be used:
200
188
  #
201
189
  # respond_to do |format|
202
190
  # format.html.none
203
191
  # format.html.phone # this gets rendered
204
192
  # end
205
- #
206
- # Be sure to check the documentation of <tt>ActionController::MimeResponds.respond_to</tt>
207
- # for more examples.
208
193
  def respond_to(*mimes)
209
194
  raise ArgumentError, "respond_to takes either types or a block, never both" if mimes.any? && block_given?
210
195
 
@@ -213,8 +198,9 @@ module ActionController #:nodoc:
213
198
 
214
199
  if format = collector.negotiate_format(request)
215
200
  _process_format(format)
201
+ _set_rendered_content_type format
216
202
  response = collector.response
217
- response ? response.call : render({})
203
+ response.call if response
218
204
  else
219
205
  raise ActionController::UnknownFormat
220
206
  end
@@ -250,7 +236,7 @@ module ActionController #:nodoc:
250
236
  @responses = {}
251
237
  @variant = variant
252
238
 
253
- mimes.each { |mime| @responses["Mime::#{mime.upcase}".constantize] = nil }
239
+ mimes.each { |mime| @responses[Mime[mime]] = nil }
254
240
  end
255
241
 
256
242
  def any(*args, &block)
@@ -296,8 +282,8 @@ module ActionController #:nodoc:
296
282
 
297
283
  def any(*args, &block)
298
284
  if block_given?
299
- if args.any? && args.none?{ |a| a == @variant }
300
- args.each{ |v| @variants[v] = block }
285
+ if args.any? && args.none? { |a| a == @variant }
286
+ args.each { |v| @variants[v] = block }
301
287
  else
302
288
  @variants[:any] = block
303
289
  end
@@ -310,16 +296,17 @@ module ActionController #:nodoc:
310
296
  end
311
297
 
312
298
  def variant
313
- if @variant.nil?
299
+ if @variant.empty?
314
300
  @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
301
  else
320
- @variants[:any]
302
+ @variants[variant_key]
321
303
  end
322
304
  end
305
+
306
+ private
307
+ def variant_key
308
+ @variant.find { |variant| @variants.key?(variant) } || :any
309
+ end
323
310
  end
324
311
  end
325
312
  end
@@ -0,0 +1,51 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActionController
4
+ # Specify binary encoding for parameters for a given action.
5
+ module ParameterEncoding
6
+ extend ActiveSupport::Concern
7
+
8
+ module ClassMethods
9
+ def inherited(klass) # :nodoc:
10
+ super
11
+ klass.setup_param_encode
12
+ end
13
+
14
+ def setup_param_encode # :nodoc:
15
+ @_parameter_encodings = {}
16
+ end
17
+
18
+ def binary_params_for?(action) # :nodoc:
19
+ @_parameter_encodings[action.to_s]
20
+ end
21
+
22
+ # Specify that a given action's parameters should all be encoded as
23
+ # ASCII-8BIT (it "skips" the encoding default of UTF-8).
24
+ #
25
+ # For example, a controller would use it like this:
26
+ #
27
+ # class RepositoryController < ActionController::Base
28
+ # skip_parameter_encoding :show
29
+ #
30
+ # def show
31
+ # @repo = Repository.find_by_filesystem_path params[:file_path]
32
+ #
33
+ # # `repo_name` is guaranteed to be UTF-8, but was ASCII-8BIT, so
34
+ # # tag it as such
35
+ # @repo_name = params[:repo_name].force_encoding 'UTF-8'
36
+ # end
37
+ #
38
+ # def index
39
+ # @repositories = Repository.all
40
+ # end
41
+ # end
42
+ #
43
+ # The show action in the above controller would have all parameter values
44
+ # encoded as ASCII-8BIT. This is useful in the case where an application
45
+ # must handle data but encoding of the data is unknown, like file system data.
46
+ def skip_parameter_encoding(action)
47
+ @_parameter_encodings[action.to_s] = true
48
+ end
49
+ end
50
+ end
51
+ end