omg-actionpack 8.0.0.alpha1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (187) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +129 -0
  3. data/MIT-LICENSE +21 -0
  4. data/README.rdoc +57 -0
  5. data/lib/abstract_controller/asset_paths.rb +14 -0
  6. data/lib/abstract_controller/base.rb +299 -0
  7. data/lib/abstract_controller/caching/fragments.rb +149 -0
  8. data/lib/abstract_controller/caching.rb +68 -0
  9. data/lib/abstract_controller/callbacks.rb +265 -0
  10. data/lib/abstract_controller/collector.rb +44 -0
  11. data/lib/abstract_controller/deprecator.rb +9 -0
  12. data/lib/abstract_controller/error.rb +8 -0
  13. data/lib/abstract_controller/helpers.rb +243 -0
  14. data/lib/abstract_controller/logger.rb +16 -0
  15. data/lib/abstract_controller/railties/routes_helpers.rb +25 -0
  16. data/lib/abstract_controller/rendering.rb +126 -0
  17. data/lib/abstract_controller/translation.rb +42 -0
  18. data/lib/abstract_controller/url_for.rb +37 -0
  19. data/lib/abstract_controller.rb +36 -0
  20. data/lib/action_controller/api/api_rendering.rb +18 -0
  21. data/lib/action_controller/api.rb +155 -0
  22. data/lib/action_controller/base.rb +332 -0
  23. data/lib/action_controller/caching.rb +49 -0
  24. data/lib/action_controller/deprecator.rb +9 -0
  25. data/lib/action_controller/form_builder.rb +55 -0
  26. data/lib/action_controller/log_subscriber.rb +96 -0
  27. data/lib/action_controller/metal/allow_browser.rb +123 -0
  28. data/lib/action_controller/metal/basic_implicit_render.rb +17 -0
  29. data/lib/action_controller/metal/conditional_get.rb +341 -0
  30. data/lib/action_controller/metal/content_security_policy.rb +86 -0
  31. data/lib/action_controller/metal/cookies.rb +20 -0
  32. data/lib/action_controller/metal/data_streaming.rb +154 -0
  33. data/lib/action_controller/metal/default_headers.rb +21 -0
  34. data/lib/action_controller/metal/etag_with_flash.rb +22 -0
  35. data/lib/action_controller/metal/etag_with_template_digest.rb +59 -0
  36. data/lib/action_controller/metal/exceptions.rb +106 -0
  37. data/lib/action_controller/metal/flash.rb +67 -0
  38. data/lib/action_controller/metal/head.rb +67 -0
  39. data/lib/action_controller/metal/helpers.rb +129 -0
  40. data/lib/action_controller/metal/http_authentication.rb +565 -0
  41. data/lib/action_controller/metal/implicit_render.rb +67 -0
  42. data/lib/action_controller/metal/instrumentation.rb +120 -0
  43. data/lib/action_controller/metal/live.rb +398 -0
  44. data/lib/action_controller/metal/logging.rb +22 -0
  45. data/lib/action_controller/metal/mime_responds.rb +337 -0
  46. data/lib/action_controller/metal/parameter_encoding.rb +84 -0
  47. data/lib/action_controller/metal/params_wrapper.rb +312 -0
  48. data/lib/action_controller/metal/permissions_policy.rb +38 -0
  49. data/lib/action_controller/metal/rate_limiting.rb +62 -0
  50. data/lib/action_controller/metal/redirecting.rb +251 -0
  51. data/lib/action_controller/metal/renderers.rb +181 -0
  52. data/lib/action_controller/metal/rendering.rb +260 -0
  53. data/lib/action_controller/metal/request_forgery_protection.rb +667 -0
  54. data/lib/action_controller/metal/rescue.rb +33 -0
  55. data/lib/action_controller/metal/streaming.rb +183 -0
  56. data/lib/action_controller/metal/strong_parameters.rb +1546 -0
  57. data/lib/action_controller/metal/testing.rb +25 -0
  58. data/lib/action_controller/metal/url_for.rb +65 -0
  59. data/lib/action_controller/metal.rb +339 -0
  60. data/lib/action_controller/railtie.rb +149 -0
  61. data/lib/action_controller/railties/helpers.rb +26 -0
  62. data/lib/action_controller/renderer.rb +161 -0
  63. data/lib/action_controller/template_assertions.rb +13 -0
  64. data/lib/action_controller/test_case.rb +691 -0
  65. data/lib/action_controller.rb +80 -0
  66. data/lib/action_dispatch/constants.rb +34 -0
  67. data/lib/action_dispatch/deprecator.rb +9 -0
  68. data/lib/action_dispatch/http/cache.rb +249 -0
  69. data/lib/action_dispatch/http/content_disposition.rb +47 -0
  70. data/lib/action_dispatch/http/content_security_policy.rb +365 -0
  71. data/lib/action_dispatch/http/filter_parameters.rb +80 -0
  72. data/lib/action_dispatch/http/filter_redirect.rb +50 -0
  73. data/lib/action_dispatch/http/headers.rb +134 -0
  74. data/lib/action_dispatch/http/mime_negotiation.rb +187 -0
  75. data/lib/action_dispatch/http/mime_type.rb +389 -0
  76. data/lib/action_dispatch/http/mime_types.rb +54 -0
  77. data/lib/action_dispatch/http/parameters.rb +119 -0
  78. data/lib/action_dispatch/http/permissions_policy.rb +189 -0
  79. data/lib/action_dispatch/http/rack_cache.rb +67 -0
  80. data/lib/action_dispatch/http/request.rb +498 -0
  81. data/lib/action_dispatch/http/response.rb +556 -0
  82. data/lib/action_dispatch/http/upload.rb +107 -0
  83. data/lib/action_dispatch/http/url.rb +344 -0
  84. data/lib/action_dispatch/journey/formatter.rb +226 -0
  85. data/lib/action_dispatch/journey/gtg/builder.rb +149 -0
  86. data/lib/action_dispatch/journey/gtg/simulator.rb +50 -0
  87. data/lib/action_dispatch/journey/gtg/transition_table.rb +217 -0
  88. data/lib/action_dispatch/journey/nfa/dot.rb +27 -0
  89. data/lib/action_dispatch/journey/nodes/node.rb +208 -0
  90. data/lib/action_dispatch/journey/parser.rb +103 -0
  91. data/lib/action_dispatch/journey/path/pattern.rb +209 -0
  92. data/lib/action_dispatch/journey/route.rb +189 -0
  93. data/lib/action_dispatch/journey/router/utils.rb +105 -0
  94. data/lib/action_dispatch/journey/router.rb +151 -0
  95. data/lib/action_dispatch/journey/routes.rb +82 -0
  96. data/lib/action_dispatch/journey/scanner.rb +70 -0
  97. data/lib/action_dispatch/journey/visitors.rb +267 -0
  98. data/lib/action_dispatch/journey/visualizer/fsm.css +30 -0
  99. data/lib/action_dispatch/journey/visualizer/fsm.js +159 -0
  100. data/lib/action_dispatch/journey/visualizer/index.html.erb +52 -0
  101. data/lib/action_dispatch/journey.rb +7 -0
  102. data/lib/action_dispatch/log_subscriber.rb +25 -0
  103. data/lib/action_dispatch/middleware/actionable_exceptions.rb +46 -0
  104. data/lib/action_dispatch/middleware/assume_ssl.rb +27 -0
  105. data/lib/action_dispatch/middleware/callbacks.rb +38 -0
  106. data/lib/action_dispatch/middleware/cookies.rb +719 -0
  107. data/lib/action_dispatch/middleware/debug_exceptions.rb +206 -0
  108. data/lib/action_dispatch/middleware/debug_locks.rb +129 -0
  109. data/lib/action_dispatch/middleware/debug_view.rb +73 -0
  110. data/lib/action_dispatch/middleware/exception_wrapper.rb +350 -0
  111. data/lib/action_dispatch/middleware/executor.rb +32 -0
  112. data/lib/action_dispatch/middleware/flash.rb +318 -0
  113. data/lib/action_dispatch/middleware/host_authorization.rb +171 -0
  114. data/lib/action_dispatch/middleware/public_exceptions.rb +64 -0
  115. data/lib/action_dispatch/middleware/reloader.rb +16 -0
  116. data/lib/action_dispatch/middleware/remote_ip.rb +199 -0
  117. data/lib/action_dispatch/middleware/request_id.rb +50 -0
  118. data/lib/action_dispatch/middleware/server_timing.rb +78 -0
  119. data/lib/action_dispatch/middleware/session/abstract_store.rb +112 -0
  120. data/lib/action_dispatch/middleware/session/cache_store.rb +66 -0
  121. data/lib/action_dispatch/middleware/session/cookie_store.rb +129 -0
  122. data/lib/action_dispatch/middleware/session/mem_cache_store.rb +34 -0
  123. data/lib/action_dispatch/middleware/show_exceptions.rb +88 -0
  124. data/lib/action_dispatch/middleware/ssl.rb +180 -0
  125. data/lib/action_dispatch/middleware/stack.rb +194 -0
  126. data/lib/action_dispatch/middleware/static.rb +192 -0
  127. data/lib/action_dispatch/middleware/templates/rescues/_actions.html.erb +13 -0
  128. data/lib/action_dispatch/middleware/templates/rescues/_actions.text.erb +0 -0
  129. data/lib/action_dispatch/middleware/templates/rescues/_message_and_suggestions.html.erb +22 -0
  130. data/lib/action_dispatch/middleware/templates/rescues/_request_and_response.html.erb +17 -0
  131. data/lib/action_dispatch/middleware/templates/rescues/_request_and_response.text.erb +23 -0
  132. data/lib/action_dispatch/middleware/templates/rescues/_source.html.erb +36 -0
  133. data/lib/action_dispatch/middleware/templates/rescues/_source.text.erb +8 -0
  134. data/lib/action_dispatch/middleware/templates/rescues/_trace.html.erb +62 -0
  135. data/lib/action_dispatch/middleware/templates/rescues/_trace.text.erb +9 -0
  136. data/lib/action_dispatch/middleware/templates/rescues/blocked_host.html.erb +12 -0
  137. data/lib/action_dispatch/middleware/templates/rescues/blocked_host.text.erb +9 -0
  138. data/lib/action_dispatch/middleware/templates/rescues/diagnostics.html.erb +35 -0
  139. data/lib/action_dispatch/middleware/templates/rescues/diagnostics.text.erb +9 -0
  140. data/lib/action_dispatch/middleware/templates/rescues/invalid_statement.html.erb +24 -0
  141. data/lib/action_dispatch/middleware/templates/rescues/invalid_statement.text.erb +16 -0
  142. data/lib/action_dispatch/middleware/templates/rescues/layout.erb +284 -0
  143. data/lib/action_dispatch/middleware/templates/rescues/missing_exact_template.html.erb +23 -0
  144. data/lib/action_dispatch/middleware/templates/rescues/missing_exact_template.text.erb +3 -0
  145. data/lib/action_dispatch/middleware/templates/rescues/missing_template.html.erb +11 -0
  146. data/lib/action_dispatch/middleware/templates/rescues/missing_template.text.erb +3 -0
  147. data/lib/action_dispatch/middleware/templates/rescues/routing_error.html.erb +32 -0
  148. data/lib/action_dispatch/middleware/templates/rescues/routing_error.text.erb +11 -0
  149. data/lib/action_dispatch/middleware/templates/rescues/template_error.html.erb +20 -0
  150. data/lib/action_dispatch/middleware/templates/rescues/template_error.text.erb +7 -0
  151. data/lib/action_dispatch/middleware/templates/rescues/unknown_action.html.erb +6 -0
  152. data/lib/action_dispatch/middleware/templates/rescues/unknown_action.text.erb +3 -0
  153. data/lib/action_dispatch/middleware/templates/routes/_route.html.erb +19 -0
  154. data/lib/action_dispatch/middleware/templates/routes/_table.html.erb +232 -0
  155. data/lib/action_dispatch/railtie.rb +77 -0
  156. data/lib/action_dispatch/request/session.rb +283 -0
  157. data/lib/action_dispatch/request/utils.rb +109 -0
  158. data/lib/action_dispatch/routing/endpoint.rb +19 -0
  159. data/lib/action_dispatch/routing/inspector.rb +323 -0
  160. data/lib/action_dispatch/routing/mapper.rb +2372 -0
  161. data/lib/action_dispatch/routing/polymorphic_routes.rb +363 -0
  162. data/lib/action_dispatch/routing/redirection.rb +218 -0
  163. data/lib/action_dispatch/routing/route_set.rb +958 -0
  164. data/lib/action_dispatch/routing/routes_proxy.rb +66 -0
  165. data/lib/action_dispatch/routing/url_for.rb +244 -0
  166. data/lib/action_dispatch/routing.rb +262 -0
  167. data/lib/action_dispatch/system_test_case.rb +206 -0
  168. data/lib/action_dispatch/system_testing/browser.rb +75 -0
  169. data/lib/action_dispatch/system_testing/driver.rb +85 -0
  170. data/lib/action_dispatch/system_testing/server.rb +33 -0
  171. data/lib/action_dispatch/system_testing/test_helpers/screenshot_helper.rb +164 -0
  172. data/lib/action_dispatch/system_testing/test_helpers/setup_and_teardown.rb +23 -0
  173. data/lib/action_dispatch/testing/assertion_response.rb +48 -0
  174. data/lib/action_dispatch/testing/assertions/response.rb +114 -0
  175. data/lib/action_dispatch/testing/assertions/routing.rb +343 -0
  176. data/lib/action_dispatch/testing/assertions.rb +25 -0
  177. data/lib/action_dispatch/testing/integration.rb +694 -0
  178. data/lib/action_dispatch/testing/request_encoder.rb +60 -0
  179. data/lib/action_dispatch/testing/test_helpers/page_dump_helper.rb +35 -0
  180. data/lib/action_dispatch/testing/test_process.rb +57 -0
  181. data/lib/action_dispatch/testing/test_request.rb +73 -0
  182. data/lib/action_dispatch/testing/test_response.rb +58 -0
  183. data/lib/action_dispatch.rb +147 -0
  184. data/lib/action_pack/gem_version.rb +19 -0
  185. data/lib/action_pack/version.rb +12 -0
  186. data/lib/action_pack.rb +27 -0
  187. metadata +375 -0
@@ -0,0 +1,337 @@
1
+ # frozen_string_literal: true
2
+
3
+ # :markup: markdown
4
+
5
+ require "abstract_controller/collector"
6
+
7
+ module ActionController # :nodoc:
8
+ module MimeResponds
9
+ # Without web-service support, an action which collects the data for displaying
10
+ # a list of people might look something like this:
11
+ #
12
+ # def index
13
+ # @people = Person.all
14
+ # end
15
+ #
16
+ # That action implicitly responds to all formats, but formats can also be
17
+ # explicitly enumerated:
18
+ #
19
+ # def index
20
+ # @people = Person.all
21
+ # respond_to :html, :js
22
+ # end
23
+ #
24
+ # Here's the same action, with web-service support baked in:
25
+ #
26
+ # def index
27
+ # @people = Person.all
28
+ #
29
+ # respond_to do |format|
30
+ # format.html
31
+ # format.js
32
+ # format.xml { render xml: @people }
33
+ # end
34
+ # end
35
+ #
36
+ # What that says is, "if the client wants HTML or JS in response to this action,
37
+ # just respond as we would have before, but if the client wants XML, return them
38
+ # the list of people in XML format." (Rails determines the desired response
39
+ # format from the HTTP Accept header submitted by the client.)
40
+ #
41
+ # Supposing you have an action that adds a new person, optionally creating their
42
+ # company (by name) if it does not already exist, without web-services, it might
43
+ # look like this:
44
+ #
45
+ # def create
46
+ # @company = Company.find_or_create_by(name: params[:company][:name])
47
+ # @person = @company.people.create(params[:person])
48
+ #
49
+ # redirect_to(person_list_url)
50
+ # end
51
+ #
52
+ # Here's the same action, with web-service support baked in:
53
+ #
54
+ # def create
55
+ # company = params[:person].delete(:company)
56
+ # @company = Company.find_or_create_by(name: company[:name])
57
+ # @person = @company.people.create(params[:person])
58
+ #
59
+ # respond_to do |format|
60
+ # format.html { redirect_to(person_list_url) }
61
+ # format.js
62
+ # format.xml { render xml: @person.to_xml(include: @company) }
63
+ # end
64
+ # end
65
+ #
66
+ # If the client wants HTML, we just redirect them back to the person list. If
67
+ # they want JavaScript, then it is an Ajax request and we render the JavaScript
68
+ # template associated with this action. Lastly, if the client wants XML, we
69
+ # render the created person as XML, but with a twist: we also include the
70
+ # person's company in the rendered XML, so you get something like this:
71
+ #
72
+ # <person>
73
+ # <id>...</id>
74
+ # ...
75
+ # <company>
76
+ # <id>...</id>
77
+ # <name>...</name>
78
+ # ...
79
+ # </company>
80
+ # </person>
81
+ #
82
+ # Note, however, the extra bit at the top of that action:
83
+ #
84
+ # company = params[:person].delete(:company)
85
+ # @company = Company.find_or_create_by(name: company[:name])
86
+ #
87
+ # This is because the incoming XML document (if a web-service request is in
88
+ # process) can only contain a single root-node. So, we have to rearrange things
89
+ # so that the request looks like this (url-encoded):
90
+ #
91
+ # person[name]=...&person[company][name]=...&...
92
+ #
93
+ # And, like this (xml-encoded):
94
+ #
95
+ # <person>
96
+ # <name>...</name>
97
+ # <company>
98
+ # <name>...</name>
99
+ # </company>
100
+ # </person>
101
+ #
102
+ # In other words, we make the request so that it operates on a single entity's
103
+ # person. Then, in the action, we extract the company data from the request,
104
+ # find or create the company, and then create the new person with the remaining
105
+ # data.
106
+ #
107
+ # Note that you can define your own XML parameter parser which would allow you
108
+ # to describe multiple entities in a single request (i.e., by wrapping them all
109
+ # in a single root node), but if you just go with the flow and accept Rails'
110
+ # defaults, life will be much easier.
111
+ #
112
+ # If you need to use a MIME type which isn't supported by default, you can
113
+ # register your own handlers in `config/initializers/mime_types.rb` as follows.
114
+ #
115
+ # Mime::Type.register "image/jpeg", :jpg
116
+ #
117
+ # `respond_to` also allows you to specify a common block for different formats
118
+ # by using `any`:
119
+ #
120
+ # def index
121
+ # @people = Person.all
122
+ #
123
+ # respond_to do |format|
124
+ # format.html
125
+ # format.any(:xml, :json) { render request.format.to_sym => @people }
126
+ # end
127
+ # end
128
+ #
129
+ # In the example above, if the format is xml, it will render:
130
+ #
131
+ # render xml: @people
132
+ #
133
+ # Or if the format is json:
134
+ #
135
+ # render json: @people
136
+ #
137
+ # `any` can also be used with no arguments, in which case it will be used for
138
+ # any format requested by the user:
139
+ #
140
+ # respond_to do |format|
141
+ # format.html
142
+ # format.any { redirect_to support_path }
143
+ # end
144
+ #
145
+ # Formats can have different variants.
146
+ #
147
+ # The request variant is a specialization of the request format, like `:tablet`,
148
+ # `:phone`, or `:desktop`.
149
+ #
150
+ # We often want to render different html/json/xml templates for phones, tablets,
151
+ # and desktop browsers. Variants make it easy.
152
+ #
153
+ # You can set the variant in a `before_action`:
154
+ #
155
+ # request.variant = :tablet if /iPad/.match?(request.user_agent)
156
+ #
157
+ # Respond to variants in the action just like you respond to formats:
158
+ #
159
+ # respond_to do |format|
160
+ # format.html do |variant|
161
+ # variant.tablet # renders app/views/projects/show.html+tablet.erb
162
+ # variant.phone { extra_setup; render ... }
163
+ # variant.none { special_setup } # executed only if there is no variant set
164
+ # end
165
+ # end
166
+ #
167
+ # Provide separate templates for each format and variant:
168
+ #
169
+ # app/views/projects/show.html.erb
170
+ # app/views/projects/show.html+tablet.erb
171
+ # app/views/projects/show.html+phone.erb
172
+ #
173
+ # When you're not sharing any code within the format, you can simplify defining
174
+ # variants using the inline syntax:
175
+ #
176
+ # respond_to do |format|
177
+ # format.js { render "trash" }
178
+ # format.html.phone { redirect_to progress_path }
179
+ # format.html.none { render "trash" }
180
+ # end
181
+ #
182
+ # Variants also support common `any`/`all` block that formats have.
183
+ #
184
+ # It works for both inline:
185
+ #
186
+ # respond_to do |format|
187
+ # format.html.any { render html: "any" }
188
+ # format.html.phone { render html: "phone" }
189
+ # end
190
+ #
191
+ # and block syntax:
192
+ #
193
+ # respond_to do |format|
194
+ # format.html do |variant|
195
+ # variant.any(:tablet, :phablet){ render html: "any" }
196
+ # variant.phone { render html: "phone" }
197
+ # end
198
+ # end
199
+ #
200
+ # You can also set an array of variants:
201
+ #
202
+ # request.variant = [:tablet, :phone]
203
+ #
204
+ # This will work similarly to formats and MIME types negotiation. If there is no
205
+ # `:tablet` variant declared, the `:phone` variant will be used:
206
+ #
207
+ # respond_to do |format|
208
+ # format.html.none
209
+ # format.html.phone # this gets rendered
210
+ # end
211
+ def respond_to(*mimes)
212
+ raise ArgumentError, "respond_to takes either types or a block, never both" if mimes.any? && block_given?
213
+
214
+ collector = Collector.new(mimes, request.variant)
215
+ yield collector if block_given?
216
+
217
+ if format = collector.negotiate_format(request)
218
+ if media_type && media_type != format
219
+ raise ActionController::RespondToMismatchError
220
+ end
221
+ _process_format(format)
222
+ _set_rendered_content_type(format) unless collector.any_response?
223
+ response = collector.response
224
+ response.call if response
225
+ else
226
+ raise ActionController::UnknownFormat
227
+ end
228
+ end
229
+
230
+ # A container for responses available from the current controller for requests
231
+ # for different mime-types sent to a particular action.
232
+ #
233
+ # The public controller methods `respond_to` may be called with a block that is
234
+ # used to define responses to different mime-types, e.g. for `respond_to` :
235
+ #
236
+ # respond_to do |format|
237
+ # format.html
238
+ # format.xml { render xml: @people }
239
+ # end
240
+ #
241
+ # In this usage, the argument passed to the block (`format` above) is an
242
+ # instance of the ActionController::MimeResponds::Collector class. This object
243
+ # serves as a container in which available responses can be stored by calling
244
+ # any of the dynamically generated, mime-type-specific methods such as `html`,
245
+ # `xml` etc on the Collector. Each response is represented by a corresponding
246
+ # block if present.
247
+ #
248
+ # A subsequent call to #negotiate_format(request) will enable the Collector to
249
+ # determine which specific mime-type it should respond with for the current
250
+ # request, with this response then being accessible by calling #response.
251
+ class Collector
252
+ include AbstractController::Collector
253
+ attr_accessor :format
254
+
255
+ def initialize(mimes, variant = nil)
256
+ @responses = {}
257
+ @variant = variant
258
+
259
+ mimes.each { |mime| @responses[Mime[mime]] = nil }
260
+ end
261
+
262
+ def any(*args, &block)
263
+ if args.any?
264
+ args.each { |type| send(type, &block) }
265
+ else
266
+ custom(Mime::ALL, &block)
267
+ end
268
+ end
269
+ alias :all :any
270
+
271
+ def custom(mime_type, &block)
272
+ mime_type = Mime::Type.lookup(mime_type.to_s) unless mime_type.is_a?(Mime::Type)
273
+ @responses[mime_type] ||= if block_given?
274
+ block
275
+ else
276
+ VariantCollector.new(@variant)
277
+ end
278
+ end
279
+
280
+ def any_response?
281
+ !@responses.fetch(format, false) && @responses[Mime::ALL]
282
+ end
283
+
284
+ def response
285
+ response = @responses.fetch(format, @responses[Mime::ALL])
286
+ if response.is_a?(VariantCollector) # `format.html.phone` - variant inline syntax
287
+ response.variant
288
+ elsif response.nil? || response.arity == 0 # `format.html` - just a format, call its block
289
+ response
290
+ else # `format.html{ |variant| variant.phone }` - variant block syntax
291
+ variant_collector = VariantCollector.new(@variant)
292
+ response.call(variant_collector) # call format block with variants collector
293
+ variant_collector.variant
294
+ end
295
+ end
296
+
297
+ def negotiate_format(request)
298
+ @format = request.negotiate_mime(@responses.keys)
299
+ end
300
+
301
+ class VariantCollector # :nodoc:
302
+ def initialize(variant = nil)
303
+ @variant = variant
304
+ @variants = {}
305
+ end
306
+
307
+ def any(*args, &block)
308
+ if block_given?
309
+ if args.any? && args.none? { |a| a == @variant }
310
+ args.each { |v| @variants[v] = block }
311
+ else
312
+ @variants[:any] = block
313
+ end
314
+ end
315
+ end
316
+ alias :all :any
317
+
318
+ def method_missing(name, *, &block)
319
+ @variants[name] = block if block_given?
320
+ end
321
+
322
+ def variant
323
+ if @variant.empty?
324
+ @variants[:none] || @variants[:any]
325
+ else
326
+ @variants[variant_key]
327
+ end
328
+ end
329
+
330
+ private
331
+ def variant_key
332
+ @variant.find { |variant| @variants.key?(variant) } || :any
333
+ end
334
+ end
335
+ end
336
+ end
337
+ end
@@ -0,0 +1,84 @@
1
+ # frozen_string_literal: true
2
+
3
+ # :markup: markdown
4
+
5
+ module ActionController
6
+ # Specify binary encoding for parameters for a given action.
7
+ module ParameterEncoding
8
+ extend ActiveSupport::Concern
9
+
10
+ module ClassMethods
11
+ def inherited(klass) # :nodoc:
12
+ super
13
+ klass.setup_param_encode
14
+ end
15
+
16
+ def setup_param_encode # :nodoc:
17
+ @_parameter_encodings = Hash.new { |h, k| h[k] = {} }
18
+ end
19
+
20
+ def action_encoding_template(action) # :nodoc:
21
+ if @_parameter_encodings.has_key?(action.to_s)
22
+ @_parameter_encodings[action.to_s]
23
+ end
24
+ end
25
+
26
+ # Specify that a given action's parameters should all be encoded as ASCII-8BIT
27
+ # (it "skips" the encoding default of UTF-8).
28
+ #
29
+ # For example, a controller would use it like this:
30
+ #
31
+ # class RepositoryController < ActionController::Base
32
+ # skip_parameter_encoding :show
33
+ #
34
+ # def show
35
+ # @repo = Repository.find_by_filesystem_path params[:file_path]
36
+ #
37
+ # # `repo_name` is guaranteed to be UTF-8, but was ASCII-8BIT, so
38
+ # # tag it as such
39
+ # @repo_name = params[:repo_name].force_encoding 'UTF-8'
40
+ # end
41
+ #
42
+ # def index
43
+ # @repositories = Repository.all
44
+ # end
45
+ # end
46
+ #
47
+ # The show action in the above controller would have all parameter values
48
+ # encoded as ASCII-8BIT. This is useful in the case where an application must
49
+ # handle data but encoding of the data is unknown, like file system data.
50
+ def skip_parameter_encoding(action)
51
+ @_parameter_encodings[action.to_s] = Hash.new { Encoding::ASCII_8BIT }
52
+ end
53
+
54
+ # Specify the encoding for a parameter on an action. If not specified the
55
+ # default is UTF-8.
56
+ #
57
+ # You can specify a binary (ASCII_8BIT) parameter with:
58
+ #
59
+ # class RepositoryController < ActionController::Base
60
+ # # This specifies that file_path is not UTF-8 and is instead ASCII_8BIT
61
+ # param_encoding :show, :file_path, Encoding::ASCII_8BIT
62
+ #
63
+ # def show
64
+ # @repo = Repository.find_by_filesystem_path params[:file_path]
65
+ #
66
+ # # params[:repo_name] remains UTF-8 encoded
67
+ # @repo_name = params[:repo_name]
68
+ # end
69
+ #
70
+ # def index
71
+ # @repositories = Repository.all
72
+ # end
73
+ # end
74
+ #
75
+ # The file_path parameter on the show action would be encoded as ASCII-8BIT, but
76
+ # all other arguments will remain UTF-8 encoded. This is useful in the case
77
+ # where an application must handle data but encoding of the data is unknown,
78
+ # like file system data.
79
+ def param_encoding(action, param, encoding)
80
+ @_parameter_encodings[action.to_s][param.to_s] = encoding
81
+ end
82
+ end
83
+ end
84
+ end