omg-actionpack 8.0.0.alpha1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/CHANGELOG.md +129 -0
- data/MIT-LICENSE +21 -0
- data/README.rdoc +57 -0
- data/lib/abstract_controller/asset_paths.rb +14 -0
- data/lib/abstract_controller/base.rb +299 -0
- data/lib/abstract_controller/caching/fragments.rb +149 -0
- data/lib/abstract_controller/caching.rb +68 -0
- data/lib/abstract_controller/callbacks.rb +265 -0
- data/lib/abstract_controller/collector.rb +44 -0
- data/lib/abstract_controller/deprecator.rb +9 -0
- data/lib/abstract_controller/error.rb +8 -0
- data/lib/abstract_controller/helpers.rb +243 -0
- data/lib/abstract_controller/logger.rb +16 -0
- data/lib/abstract_controller/railties/routes_helpers.rb +25 -0
- data/lib/abstract_controller/rendering.rb +126 -0
- data/lib/abstract_controller/translation.rb +42 -0
- data/lib/abstract_controller/url_for.rb +37 -0
- data/lib/abstract_controller.rb +36 -0
- data/lib/action_controller/api/api_rendering.rb +18 -0
- data/lib/action_controller/api.rb +155 -0
- data/lib/action_controller/base.rb +332 -0
- data/lib/action_controller/caching.rb +49 -0
- data/lib/action_controller/deprecator.rb +9 -0
- data/lib/action_controller/form_builder.rb +55 -0
- data/lib/action_controller/log_subscriber.rb +96 -0
- data/lib/action_controller/metal/allow_browser.rb +123 -0
- data/lib/action_controller/metal/basic_implicit_render.rb +17 -0
- data/lib/action_controller/metal/conditional_get.rb +341 -0
- data/lib/action_controller/metal/content_security_policy.rb +86 -0
- data/lib/action_controller/metal/cookies.rb +20 -0
- data/lib/action_controller/metal/data_streaming.rb +154 -0
- data/lib/action_controller/metal/default_headers.rb +21 -0
- data/lib/action_controller/metal/etag_with_flash.rb +22 -0
- data/lib/action_controller/metal/etag_with_template_digest.rb +59 -0
- data/lib/action_controller/metal/exceptions.rb +106 -0
- data/lib/action_controller/metal/flash.rb +67 -0
- data/lib/action_controller/metal/head.rb +67 -0
- data/lib/action_controller/metal/helpers.rb +129 -0
- data/lib/action_controller/metal/http_authentication.rb +565 -0
- data/lib/action_controller/metal/implicit_render.rb +67 -0
- data/lib/action_controller/metal/instrumentation.rb +120 -0
- data/lib/action_controller/metal/live.rb +398 -0
- data/lib/action_controller/metal/logging.rb +22 -0
- data/lib/action_controller/metal/mime_responds.rb +337 -0
- data/lib/action_controller/metal/parameter_encoding.rb +84 -0
- data/lib/action_controller/metal/params_wrapper.rb +312 -0
- data/lib/action_controller/metal/permissions_policy.rb +38 -0
- data/lib/action_controller/metal/rate_limiting.rb +62 -0
- data/lib/action_controller/metal/redirecting.rb +251 -0
- data/lib/action_controller/metal/renderers.rb +181 -0
- data/lib/action_controller/metal/rendering.rb +260 -0
- data/lib/action_controller/metal/request_forgery_protection.rb +667 -0
- data/lib/action_controller/metal/rescue.rb +33 -0
- data/lib/action_controller/metal/streaming.rb +183 -0
- data/lib/action_controller/metal/strong_parameters.rb +1546 -0
- data/lib/action_controller/metal/testing.rb +25 -0
- data/lib/action_controller/metal/url_for.rb +65 -0
- data/lib/action_controller/metal.rb +339 -0
- data/lib/action_controller/railtie.rb +149 -0
- data/lib/action_controller/railties/helpers.rb +26 -0
- data/lib/action_controller/renderer.rb +161 -0
- data/lib/action_controller/template_assertions.rb +13 -0
- data/lib/action_controller/test_case.rb +691 -0
- data/lib/action_controller.rb +80 -0
- data/lib/action_dispatch/constants.rb +34 -0
- data/lib/action_dispatch/deprecator.rb +9 -0
- data/lib/action_dispatch/http/cache.rb +249 -0
- data/lib/action_dispatch/http/content_disposition.rb +47 -0
- data/lib/action_dispatch/http/content_security_policy.rb +365 -0
- data/lib/action_dispatch/http/filter_parameters.rb +80 -0
- data/lib/action_dispatch/http/filter_redirect.rb +50 -0
- data/lib/action_dispatch/http/headers.rb +134 -0
- data/lib/action_dispatch/http/mime_negotiation.rb +187 -0
- data/lib/action_dispatch/http/mime_type.rb +389 -0
- data/lib/action_dispatch/http/mime_types.rb +54 -0
- data/lib/action_dispatch/http/parameters.rb +119 -0
- data/lib/action_dispatch/http/permissions_policy.rb +189 -0
- data/lib/action_dispatch/http/rack_cache.rb +67 -0
- data/lib/action_dispatch/http/request.rb +498 -0
- data/lib/action_dispatch/http/response.rb +556 -0
- data/lib/action_dispatch/http/upload.rb +107 -0
- data/lib/action_dispatch/http/url.rb +344 -0
- data/lib/action_dispatch/journey/formatter.rb +226 -0
- data/lib/action_dispatch/journey/gtg/builder.rb +149 -0
- data/lib/action_dispatch/journey/gtg/simulator.rb +50 -0
- data/lib/action_dispatch/journey/gtg/transition_table.rb +217 -0
- data/lib/action_dispatch/journey/nfa/dot.rb +27 -0
- data/lib/action_dispatch/journey/nodes/node.rb +208 -0
- data/lib/action_dispatch/journey/parser.rb +103 -0
- data/lib/action_dispatch/journey/path/pattern.rb +209 -0
- data/lib/action_dispatch/journey/route.rb +189 -0
- data/lib/action_dispatch/journey/router/utils.rb +105 -0
- data/lib/action_dispatch/journey/router.rb +151 -0
- data/lib/action_dispatch/journey/routes.rb +82 -0
- data/lib/action_dispatch/journey/scanner.rb +70 -0
- data/lib/action_dispatch/journey/visitors.rb +267 -0
- data/lib/action_dispatch/journey/visualizer/fsm.css +30 -0
- data/lib/action_dispatch/journey/visualizer/fsm.js +159 -0
- data/lib/action_dispatch/journey/visualizer/index.html.erb +52 -0
- data/lib/action_dispatch/journey.rb +7 -0
- data/lib/action_dispatch/log_subscriber.rb +25 -0
- data/lib/action_dispatch/middleware/actionable_exceptions.rb +46 -0
- data/lib/action_dispatch/middleware/assume_ssl.rb +27 -0
- data/lib/action_dispatch/middleware/callbacks.rb +38 -0
- data/lib/action_dispatch/middleware/cookies.rb +719 -0
- data/lib/action_dispatch/middleware/debug_exceptions.rb +206 -0
- data/lib/action_dispatch/middleware/debug_locks.rb +129 -0
- data/lib/action_dispatch/middleware/debug_view.rb +73 -0
- data/lib/action_dispatch/middleware/exception_wrapper.rb +350 -0
- data/lib/action_dispatch/middleware/executor.rb +32 -0
- data/lib/action_dispatch/middleware/flash.rb +318 -0
- data/lib/action_dispatch/middleware/host_authorization.rb +171 -0
- data/lib/action_dispatch/middleware/public_exceptions.rb +64 -0
- data/lib/action_dispatch/middleware/reloader.rb +16 -0
- data/lib/action_dispatch/middleware/remote_ip.rb +199 -0
- data/lib/action_dispatch/middleware/request_id.rb +50 -0
- data/lib/action_dispatch/middleware/server_timing.rb +78 -0
- data/lib/action_dispatch/middleware/session/abstract_store.rb +112 -0
- data/lib/action_dispatch/middleware/session/cache_store.rb +66 -0
- data/lib/action_dispatch/middleware/session/cookie_store.rb +129 -0
- data/lib/action_dispatch/middleware/session/mem_cache_store.rb +34 -0
- data/lib/action_dispatch/middleware/show_exceptions.rb +88 -0
- data/lib/action_dispatch/middleware/ssl.rb +180 -0
- data/lib/action_dispatch/middleware/stack.rb +194 -0
- data/lib/action_dispatch/middleware/static.rb +192 -0
- data/lib/action_dispatch/middleware/templates/rescues/_actions.html.erb +13 -0
- data/lib/action_dispatch/middleware/templates/rescues/_actions.text.erb +0 -0
- data/lib/action_dispatch/middleware/templates/rescues/_message_and_suggestions.html.erb +22 -0
- data/lib/action_dispatch/middleware/templates/rescues/_request_and_response.html.erb +17 -0
- data/lib/action_dispatch/middleware/templates/rescues/_request_and_response.text.erb +23 -0
- data/lib/action_dispatch/middleware/templates/rescues/_source.html.erb +36 -0
- data/lib/action_dispatch/middleware/templates/rescues/_source.text.erb +8 -0
- data/lib/action_dispatch/middleware/templates/rescues/_trace.html.erb +62 -0
- data/lib/action_dispatch/middleware/templates/rescues/_trace.text.erb +9 -0
- data/lib/action_dispatch/middleware/templates/rescues/blocked_host.html.erb +12 -0
- data/lib/action_dispatch/middleware/templates/rescues/blocked_host.text.erb +9 -0
- data/lib/action_dispatch/middleware/templates/rescues/diagnostics.html.erb +35 -0
- data/lib/action_dispatch/middleware/templates/rescues/diagnostics.text.erb +9 -0
- data/lib/action_dispatch/middleware/templates/rescues/invalid_statement.html.erb +24 -0
- data/lib/action_dispatch/middleware/templates/rescues/invalid_statement.text.erb +16 -0
- data/lib/action_dispatch/middleware/templates/rescues/layout.erb +284 -0
- data/lib/action_dispatch/middleware/templates/rescues/missing_exact_template.html.erb +23 -0
- data/lib/action_dispatch/middleware/templates/rescues/missing_exact_template.text.erb +3 -0
- data/lib/action_dispatch/middleware/templates/rescues/missing_template.html.erb +11 -0
- data/lib/action_dispatch/middleware/templates/rescues/missing_template.text.erb +3 -0
- data/lib/action_dispatch/middleware/templates/rescues/routing_error.html.erb +32 -0
- data/lib/action_dispatch/middleware/templates/rescues/routing_error.text.erb +11 -0
- data/lib/action_dispatch/middleware/templates/rescues/template_error.html.erb +20 -0
- data/lib/action_dispatch/middleware/templates/rescues/template_error.text.erb +7 -0
- data/lib/action_dispatch/middleware/templates/rescues/unknown_action.html.erb +6 -0
- data/lib/action_dispatch/middleware/templates/rescues/unknown_action.text.erb +3 -0
- data/lib/action_dispatch/middleware/templates/routes/_route.html.erb +19 -0
- data/lib/action_dispatch/middleware/templates/routes/_table.html.erb +232 -0
- data/lib/action_dispatch/railtie.rb +77 -0
- data/lib/action_dispatch/request/session.rb +283 -0
- data/lib/action_dispatch/request/utils.rb +109 -0
- data/lib/action_dispatch/routing/endpoint.rb +19 -0
- data/lib/action_dispatch/routing/inspector.rb +323 -0
- data/lib/action_dispatch/routing/mapper.rb +2372 -0
- data/lib/action_dispatch/routing/polymorphic_routes.rb +363 -0
- data/lib/action_dispatch/routing/redirection.rb +218 -0
- data/lib/action_dispatch/routing/route_set.rb +958 -0
- data/lib/action_dispatch/routing/routes_proxy.rb +66 -0
- data/lib/action_dispatch/routing/url_for.rb +244 -0
- data/lib/action_dispatch/routing.rb +262 -0
- data/lib/action_dispatch/system_test_case.rb +206 -0
- data/lib/action_dispatch/system_testing/browser.rb +75 -0
- data/lib/action_dispatch/system_testing/driver.rb +85 -0
- data/lib/action_dispatch/system_testing/server.rb +33 -0
- data/lib/action_dispatch/system_testing/test_helpers/screenshot_helper.rb +164 -0
- data/lib/action_dispatch/system_testing/test_helpers/setup_and_teardown.rb +23 -0
- data/lib/action_dispatch/testing/assertion_response.rb +48 -0
- data/lib/action_dispatch/testing/assertions/response.rb +114 -0
- data/lib/action_dispatch/testing/assertions/routing.rb +343 -0
- data/lib/action_dispatch/testing/assertions.rb +25 -0
- data/lib/action_dispatch/testing/integration.rb +694 -0
- data/lib/action_dispatch/testing/request_encoder.rb +60 -0
- data/lib/action_dispatch/testing/test_helpers/page_dump_helper.rb +35 -0
- data/lib/action_dispatch/testing/test_process.rb +57 -0
- data/lib/action_dispatch/testing/test_request.rb +73 -0
- data/lib/action_dispatch/testing/test_response.rb +58 -0
- data/lib/action_dispatch.rb +147 -0
- data/lib/action_pack/gem_version.rb +19 -0
- data/lib/action_pack/version.rb +12 -0
- data/lib/action_pack.rb +27 -0
- 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
|