actionpack 4.0.1 → 4.2.11.1

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 (241) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +402 -1173
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +7 -7
  5. data/lib/abstract_controller/base.rb +39 -7
  6. data/lib/abstract_controller/callbacks.rb +32 -53
  7. data/lib/abstract_controller/collector.rb +11 -1
  8. data/lib/abstract_controller/helpers.rb +26 -16
  9. data/lib/abstract_controller/railties/routes_helpers.rb +3 -3
  10. data/lib/abstract_controller/rendering.rb +57 -127
  11. data/lib/abstract_controller/url_for.rb +1 -1
  12. data/lib/abstract_controller.rb +1 -2
  13. data/lib/action_controller/base.rb +19 -10
  14. data/lib/action_controller/caching/fragments.rb +7 -1
  15. data/lib/action_controller/caching.rb +2 -12
  16. data/lib/action_controller/log_subscriber.rb +29 -20
  17. data/lib/action_controller/metal/conditional_get.rb +37 -12
  18. data/lib/action_controller/metal/data_streaming.rb +1 -1
  19. data/lib/action_controller/metal/etag_with_template_digest.rb +50 -0
  20. data/lib/action_controller/metal/exceptions.rb +1 -1
  21. data/lib/action_controller/metal/flash.rb +17 -0
  22. data/lib/action_controller/metal/force_ssl.rb +2 -2
  23. data/lib/action_controller/metal/head.rb +8 -6
  24. data/lib/action_controller/metal/helpers.rb +6 -2
  25. data/lib/action_controller/metal/http_authentication.rb +45 -23
  26. data/lib/action_controller/metal/instrumentation.rb +9 -6
  27. data/lib/action_controller/metal/live.rb +173 -20
  28. data/lib/action_controller/metal/mime_responds.rb +127 -232
  29. data/lib/action_controller/metal/params_wrapper.rb +16 -9
  30. data/lib/action_controller/metal/rack_delegation.rb +1 -1
  31. data/lib/action_controller/metal/redirecting.rb +34 -26
  32. data/lib/action_controller/metal/renderers.rb +39 -12
  33. data/lib/action_controller/metal/rendering.rb +41 -14
  34. data/lib/action_controller/metal/request_forgery_protection.rb +147 -19
  35. data/lib/action_controller/metal/streaming.rb +19 -21
  36. data/lib/action_controller/metal/strong_parameters.rb +166 -22
  37. data/lib/action_controller/metal/testing.rb +0 -1
  38. data/lib/action_controller/metal/url_for.rb +11 -12
  39. data/lib/action_controller/metal.rb +14 -8
  40. data/lib/action_controller/model_naming.rb +1 -1
  41. data/lib/action_controller/railtie.rb +5 -1
  42. data/lib/action_controller/test_case.rb +160 -94
  43. data/lib/action_controller.rb +2 -18
  44. data/lib/action_dispatch/http/cache.rb +5 -4
  45. data/lib/action_dispatch/http/filter_parameters.rb +2 -2
  46. data/lib/action_dispatch/http/filter_redirect.rb +5 -4
  47. data/lib/action_dispatch/http/headers.rb +46 -10
  48. data/lib/action_dispatch/http/mime_negotiation.rb +31 -4
  49. data/lib/action_dispatch/http/mime_type.rb +25 -26
  50. data/lib/action_dispatch/http/mime_types.rb +1 -0
  51. data/lib/action_dispatch/http/parameter_filter.rb +1 -1
  52. data/lib/action_dispatch/http/parameters.rb +25 -41
  53. data/lib/action_dispatch/http/request.rb +49 -32
  54. data/lib/action_dispatch/http/response.rb +127 -25
  55. data/lib/action_dispatch/http/upload.rb +9 -21
  56. data/lib/action_dispatch/http/url.rb +97 -70
  57. data/lib/action_dispatch/journey/formatter.rb +35 -19
  58. data/lib/action_dispatch/journey/gtg/builder.rb +3 -3
  59. data/lib/action_dispatch/journey/gtg/simulator.rb +10 -7
  60. data/lib/action_dispatch/journey/gtg/transition_table.rb +23 -33
  61. data/lib/action_dispatch/journey/nfa/dot.rb +2 -2
  62. data/lib/action_dispatch/journey/nfa/simulator.rb +1 -1
  63. data/lib/action_dispatch/journey/nfa/transition_table.rb +5 -5
  64. data/lib/action_dispatch/journey/nodes/node.rb +4 -0
  65. data/lib/action_dispatch/journey/parser.rb +51 -59
  66. data/lib/action_dispatch/journey/parser.y +12 -10
  67. data/lib/action_dispatch/journey/path/pattern.rb +16 -19
  68. data/lib/action_dispatch/journey/route.rb +8 -19
  69. data/lib/action_dispatch/journey/router/strexp.rb +9 -6
  70. data/lib/action_dispatch/journey/router/utils.rb +54 -18
  71. data/lib/action_dispatch/journey/router.rb +53 -75
  72. data/lib/action_dispatch/journey/routes.rb +4 -0
  73. data/lib/action_dispatch/journey/scanner.rb +5 -5
  74. data/lib/action_dispatch/journey/visitors.rb +81 -60
  75. data/lib/action_dispatch/journey/visualizer/fsm.css +0 -4
  76. data/lib/action_dispatch/journey/visualizer/index.html.erb +2 -2
  77. data/lib/action_dispatch/middleware/callbacks.rb +7 -7
  78. data/lib/action_dispatch/middleware/cookies.rb +119 -43
  79. data/lib/action_dispatch/middleware/debug_exceptions.rb +32 -13
  80. data/lib/action_dispatch/middleware/exception_wrapper.rb +60 -20
  81. data/lib/action_dispatch/middleware/flash.rb +37 -24
  82. data/lib/action_dispatch/middleware/params_parser.rb +2 -2
  83. data/lib/action_dispatch/middleware/public_exceptions.rb +12 -3
  84. data/lib/action_dispatch/middleware/reloader.rb +11 -2
  85. data/lib/action_dispatch/middleware/remote_ip.rb +40 -54
  86. data/lib/action_dispatch/middleware/request_id.rb +1 -1
  87. data/lib/action_dispatch/middleware/session/cache_store.rb +3 -3
  88. data/lib/action_dispatch/middleware/session/cookie_store.rb +8 -7
  89. data/lib/action_dispatch/middleware/show_exceptions.rb +6 -2
  90. data/lib/action_dispatch/middleware/ssl.rb +10 -7
  91. data/lib/action_dispatch/middleware/static.rb +79 -23
  92. data/lib/action_dispatch/middleware/templates/rescues/{_request_and_response.erb → _request_and_response.html.erb} +0 -0
  93. data/lib/action_dispatch/middleware/templates/rescues/_request_and_response.text.erb +23 -0
  94. data/lib/action_dispatch/middleware/templates/rescues/_source.erb +21 -19
  95. data/lib/action_dispatch/middleware/templates/rescues/_trace.html.erb +52 -0
  96. data/lib/action_dispatch/middleware/templates/rescues/_trace.text.erb +9 -0
  97. data/lib/action_dispatch/middleware/templates/rescues/{diagnostics.erb → diagnostics.html.erb} +1 -1
  98. data/lib/action_dispatch/middleware/templates/rescues/diagnostics.text.erb +9 -0
  99. data/lib/action_dispatch/middleware/templates/rescues/layout.erb +6 -0
  100. data/lib/action_dispatch/middleware/templates/rescues/missing_template.html.erb +11 -0
  101. data/lib/action_dispatch/middleware/templates/rescues/missing_template.text.erb +3 -0
  102. data/lib/action_dispatch/middleware/templates/rescues/{routing_error.erb → routing_error.html.erb} +3 -1
  103. data/lib/action_dispatch/middleware/templates/rescues/routing_error.text.erb +11 -0
  104. data/lib/action_dispatch/middleware/templates/rescues/template_error.html.erb +20 -0
  105. data/lib/action_dispatch/middleware/templates/rescues/template_error.text.erb +7 -0
  106. data/lib/action_dispatch/middleware/templates/rescues/{unknown_action.erb → unknown_action.html.erb} +1 -1
  107. data/lib/action_dispatch/middleware/templates/rescues/unknown_action.text.erb +3 -0
  108. data/lib/action_dispatch/middleware/templates/routes/_table.html.erb +120 -64
  109. data/lib/action_dispatch/railtie.rb +5 -2
  110. data/lib/action_dispatch/request/session.rb +12 -0
  111. data/lib/action_dispatch/request/utils.rb +35 -0
  112. data/lib/action_dispatch/routing/endpoint.rb +10 -0
  113. data/lib/action_dispatch/routing/inspector.rb +11 -17
  114. data/lib/action_dispatch/routing/mapper.rb +519 -312
  115. data/lib/action_dispatch/routing/polymorphic_routes.rb +204 -79
  116. data/lib/action_dispatch/routing/redirection.rb +51 -26
  117. data/lib/action_dispatch/routing/route_set.rb +331 -206
  118. data/lib/action_dispatch/routing/routes_proxy.rb +5 -4
  119. data/lib/action_dispatch/routing/url_for.rb +19 -5
  120. data/lib/action_dispatch/routing.rb +9 -6
  121. data/lib/action_dispatch/testing/assertions/dom.rb +2 -26
  122. data/lib/action_dispatch/testing/assertions/response.rb +9 -15
  123. data/lib/action_dispatch/testing/assertions/routing.rb +22 -22
  124. data/lib/action_dispatch/testing/assertions/selector.rb +2 -429
  125. data/lib/action_dispatch/testing/assertions/tag.rb +2 -134
  126. data/lib/action_dispatch/testing/assertions.rb +11 -7
  127. data/lib/action_dispatch/testing/integration.rb +31 -29
  128. data/lib/action_dispatch/testing/test_request.rb +1 -1
  129. data/lib/action_dispatch/testing/test_response.rb +1 -5
  130. data/lib/action_dispatch.rb +5 -8
  131. data/lib/action_pack/gem_version.rb +15 -0
  132. data/lib/action_pack/version.rb +4 -7
  133. data/lib/action_pack.rb +1 -1
  134. metadata +77 -159
  135. data/lib/abstract_controller/layouts.rb +0 -423
  136. data/lib/abstract_controller/view_paths.rb +0 -96
  137. data/lib/action_controller/deprecated/integration_test.rb +0 -5
  138. data/lib/action_controller/deprecated.rb +0 -7
  139. data/lib/action_controller/metal/responder.rb +0 -287
  140. data/lib/action_controller/record_identifier.rb +0 -31
  141. data/lib/action_controller/vendor/html-scanner.rb +0 -5
  142. data/lib/action_dispatch/middleware/templates/rescues/_trace.erb +0 -24
  143. data/lib/action_dispatch/middleware/templates/rescues/missing_template.erb +0 -7
  144. data/lib/action_dispatch/middleware/templates/rescues/template_error.erb +0 -43
  145. data/lib/action_view/base.rb +0 -201
  146. data/lib/action_view/buffers.rb +0 -49
  147. data/lib/action_view/context.rb +0 -36
  148. data/lib/action_view/dependency_tracker.rb +0 -93
  149. data/lib/action_view/digestor.rb +0 -113
  150. data/lib/action_view/flows.rb +0 -76
  151. data/lib/action_view/helpers/active_model_helper.rb +0 -49
  152. data/lib/action_view/helpers/asset_tag_helper.rb +0 -320
  153. data/lib/action_view/helpers/asset_url_helper.rb +0 -355
  154. data/lib/action_view/helpers/atom_feed_helper.rb +0 -203
  155. data/lib/action_view/helpers/cache_helper.rb +0 -196
  156. data/lib/action_view/helpers/capture_helper.rb +0 -216
  157. data/lib/action_view/helpers/controller_helper.rb +0 -25
  158. data/lib/action_view/helpers/csrf_helper.rb +0 -30
  159. data/lib/action_view/helpers/date_helper.rb +0 -1083
  160. data/lib/action_view/helpers/debug_helper.rb +0 -39
  161. data/lib/action_view/helpers/form_helper.rb +0 -1880
  162. data/lib/action_view/helpers/form_options_helper.rb +0 -838
  163. data/lib/action_view/helpers/form_tag_helper.rb +0 -785
  164. data/lib/action_view/helpers/javascript_helper.rb +0 -117
  165. data/lib/action_view/helpers/number_helper.rb +0 -441
  166. data/lib/action_view/helpers/output_safety_helper.rb +0 -38
  167. data/lib/action_view/helpers/record_tag_helper.rb +0 -106
  168. data/lib/action_view/helpers/rendering_helper.rb +0 -90
  169. data/lib/action_view/helpers/sanitize_helper.rb +0 -256
  170. data/lib/action_view/helpers/tag_helper.rb +0 -173
  171. data/lib/action_view/helpers/tags/base.rb +0 -148
  172. data/lib/action_view/helpers/tags/check_box.rb +0 -64
  173. data/lib/action_view/helpers/tags/checkable.rb +0 -16
  174. data/lib/action_view/helpers/tags/collection_check_boxes.rb +0 -44
  175. data/lib/action_view/helpers/tags/collection_helpers.rb +0 -84
  176. data/lib/action_view/helpers/tags/collection_radio_buttons.rb +0 -36
  177. data/lib/action_view/helpers/tags/collection_select.rb +0 -28
  178. data/lib/action_view/helpers/tags/color_field.rb +0 -25
  179. data/lib/action_view/helpers/tags/date_field.rb +0 -13
  180. data/lib/action_view/helpers/tags/date_select.rb +0 -72
  181. data/lib/action_view/helpers/tags/datetime_field.rb +0 -22
  182. data/lib/action_view/helpers/tags/datetime_local_field.rb +0 -19
  183. data/lib/action_view/helpers/tags/datetime_select.rb +0 -8
  184. data/lib/action_view/helpers/tags/email_field.rb +0 -8
  185. data/lib/action_view/helpers/tags/file_field.rb +0 -8
  186. data/lib/action_view/helpers/tags/grouped_collection_select.rb +0 -29
  187. data/lib/action_view/helpers/tags/hidden_field.rb +0 -8
  188. data/lib/action_view/helpers/tags/label.rb +0 -66
  189. data/lib/action_view/helpers/tags/month_field.rb +0 -13
  190. data/lib/action_view/helpers/tags/number_field.rb +0 -18
  191. data/lib/action_view/helpers/tags/password_field.rb +0 -12
  192. data/lib/action_view/helpers/tags/radio_button.rb +0 -31
  193. data/lib/action_view/helpers/tags/range_field.rb +0 -8
  194. data/lib/action_view/helpers/tags/search_field.rb +0 -24
  195. data/lib/action_view/helpers/tags/select.rb +0 -40
  196. data/lib/action_view/helpers/tags/tel_field.rb +0 -8
  197. data/lib/action_view/helpers/tags/text_area.rb +0 -18
  198. data/lib/action_view/helpers/tags/text_field.rb +0 -29
  199. data/lib/action_view/helpers/tags/time_field.rb +0 -13
  200. data/lib/action_view/helpers/tags/time_select.rb +0 -8
  201. data/lib/action_view/helpers/tags/time_zone_select.rb +0 -20
  202. data/lib/action_view/helpers/tags/url_field.rb +0 -8
  203. data/lib/action_view/helpers/tags/week_field.rb +0 -13
  204. data/lib/action_view/helpers/tags.rb +0 -39
  205. data/lib/action_view/helpers/text_helper.rb +0 -443
  206. data/lib/action_view/helpers/translation_helper.rb +0 -107
  207. data/lib/action_view/helpers/url_helper.rb +0 -635
  208. data/lib/action_view/helpers.rb +0 -58
  209. data/lib/action_view/locale/en.yml +0 -56
  210. data/lib/action_view/log_subscriber.rb +0 -30
  211. data/lib/action_view/lookup_context.rb +0 -241
  212. data/lib/action_view/model_naming.rb +0 -12
  213. data/lib/action_view/path_set.rb +0 -77
  214. data/lib/action_view/railtie.rb +0 -43
  215. data/lib/action_view/record_identifier.rb +0 -84
  216. data/lib/action_view/renderer/abstract_renderer.rb +0 -47
  217. data/lib/action_view/renderer/partial_renderer.rb +0 -492
  218. data/lib/action_view/renderer/renderer.rb +0 -50
  219. data/lib/action_view/renderer/streaming_template_renderer.rb +0 -103
  220. data/lib/action_view/renderer/template_renderer.rb +0 -96
  221. data/lib/action_view/routing_url_for.rb +0 -107
  222. data/lib/action_view/tasks/dependencies.rake +0 -17
  223. data/lib/action_view/template/error.rb +0 -138
  224. data/lib/action_view/template/handlers/builder.rb +0 -26
  225. data/lib/action_view/template/handlers/erb.rb +0 -146
  226. data/lib/action_view/template/handlers/raw.rb +0 -11
  227. data/lib/action_view/template/handlers.rb +0 -53
  228. data/lib/action_view/template/resolver.rb +0 -326
  229. data/lib/action_view/template/text.rb +0 -34
  230. data/lib/action_view/template/types.rb +0 -57
  231. data/lib/action_view/template.rb +0 -339
  232. data/lib/action_view/test_case.rb +0 -270
  233. data/lib/action_view/testing/resolvers.rb +0 -50
  234. data/lib/action_view/vendor/html-scanner/html/document.rb +0 -68
  235. data/lib/action_view/vendor/html-scanner/html/node.rb +0 -532
  236. data/lib/action_view/vendor/html-scanner/html/sanitizer.rb +0 -188
  237. data/lib/action_view/vendor/html-scanner/html/selector.rb +0 -830
  238. data/lib/action_view/vendor/html-scanner/html/tokenizer.rb +0 -107
  239. data/lib/action_view/vendor/html-scanner/html/version.rb +0 -11
  240. data/lib/action_view/vendor/html-scanner.rb +0 -20
  241. data/lib/action_view.rb +0 -93
@@ -1,61 +1,28 @@
1
- require 'active_support/core_ext/array/extract_options'
2
1
  require 'abstract_controller/collector'
3
2
 
4
3
  module ActionController #:nodoc:
5
4
  module MimeResponds
6
5
  extend ActiveSupport::Concern
7
6
 
8
- included do
9
- class_attribute :responder, :mimes_for_respond_to
10
- self.responder = ActionController::Responder
11
- clear_respond_to
12
- end
13
-
7
+ # :stopdoc:
14
8
  module ClassMethods
15
- # Defines mime types that are rendered by default when invoking
16
- # <tt>respond_with</tt>.
17
- #
18
- # respond_to :html, :xml, :json
19
- #
20
- # Specifies that all actions in the controller respond to requests
21
- # for <tt>:html</tt>, <tt>:xml</tt> and <tt>:json</tt>.
22
- #
23
- # To specify on per-action basis, use <tt>:only</tt> and
24
- # <tt>:except</tt> with an array of actions or a single action:
25
- #
26
- # respond_to :html
27
- # respond_to :xml, :json, except: [ :edit ]
28
- #
29
- # This specifies that all actions respond to <tt>:html</tt>
30
- # and all actions except <tt>:edit</tt> respond to <tt>:xml</tt> and
31
- # <tt>:json</tt>.
32
- #
33
- # respond_to :json, only: :create
34
- #
35
- # This specifies that the <tt>:create</tt> action and no other responds
36
- # to <tt>:json</tt>.
37
- def respond_to(*mimes)
38
- options = mimes.extract_options!
39
-
40
- only_actions = Array(options.delete(:only)).map(&:to_s)
41
- except_actions = Array(options.delete(:except)).map(&:to_s)
42
-
43
- new = mimes_for_respond_to.dup
44
- mimes.each do |mime|
45
- mime = mime.to_sym
46
- new[mime] = {}
47
- new[mime][:only] = only_actions unless only_actions.empty?
48
- new[mime][:except] = except_actions unless except_actions.empty?
49
- end
50
- self.mimes_for_respond_to = new.freeze
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."
51
15
  end
16
+ end
52
17
 
53
- # Clear all mime types in <tt>respond_to</tt>.
54
- #
55
- def clear_respond_to
56
- self.mimes_for_respond_to = Hash.new.freeze
57
- end
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."
58
24
  end
25
+ # :startdoc:
59
26
 
60
27
  # Without web-service support, an action which collects the data for displaying a list of people
61
28
  # might look something like this:
@@ -169,205 +136,85 @@ module ActionController #:nodoc:
169
136
  #
170
137
  # render json: @people
171
138
  #
172
- # Since this is a common pattern, you can use the class method respond_to
173
- # with the respond_with method to have the same results:
139
+ # Formats can have different variants.
174
140
  #
175
- # class PeopleController < ApplicationController
176
- # respond_to :html, :xml, :json
141
+ # The request variant is a specialization of the request format, like <tt>:tablet</tt>,
142
+ # <tt>:phone</tt>, or <tt>:desktop</tt>.
177
143
  #
178
- # def index
179
- # @people = Person.all
180
- # respond_with(@people)
181
- # end
182
- # end
144
+ # We often want to render different html/json/xml templates for phones,
145
+ # tablets, and desktop browsers. Variants make it easy.
183
146
  #
184
- # Be sure to check the documentation of +respond_with+ and
185
- # <tt>ActionController::MimeResponds.respond_to</tt> for more examples.
186
- def respond_to(*mimes, &block)
187
- raise ArgumentError, "respond_to takes either types or a block, never both" if mimes.any? && block_given?
188
-
189
- if collector = retrieve_collector_from_mimes(mimes, &block)
190
- response = collector.response
191
- response ? response.call : render({})
192
- end
193
- end
194
-
195
- # For a given controller action, respond_with generates an appropriate
196
- # response based on the mime-type requested by the client.
147
+ # You can set the variant in a +before_action+:
197
148
  #
198
- # If the method is called with just a resource, as in this example -
149
+ # request.variant = :tablet if request.user_agent =~ /iPad/
199
150
  #
200
- # class PeopleController < ApplicationController
201
- # respond_to :html, :xml, :json
151
+ # Respond to variants in the action just like you respond to formats:
202
152
  #
203
- # def index
204
- # @people = Person.all
205
- # respond_with @people
153
+ # respond_to do |format|
154
+ # format.html do |variant|
155
+ # variant.tablet # renders app/views/projects/show.html+tablet.erb
156
+ # variant.phone { extra_setup; render ... }
157
+ # variant.none { special_setup } # executed only if there is no variant set
206
158
  # end
207
159
  # end
208
160
  #
209
- # then the mime-type of the response is typically selected based on the
210
- # request's Accept header and the set of available formats declared
211
- # by previous calls to the controller's class method +respond_to+. Alternatively
212
- # the mime-type can be selected by explicitly setting <tt>request.format</tt> in
213
- # the controller.
214
- #
215
- # If an acceptable format is not identified, the application returns a
216
- # '406 - not acceptable' status. Otherwise, the default response is to render
217
- # a template named after the current action and the selected format,
218
- # e.g. <tt>index.html.erb</tt>. If no template is available, the behavior
219
- # depends on the selected format:
220
- #
221
- # * for an html response - if the request method is +get+, an exception
222
- # is raised but for other requests such as +post+ the response
223
- # depends on whether the resource has any validation errors (i.e.
224
- # assuming that an attempt has been made to save the resource,
225
- # e.g. by a +create+ action) -
226
- # 1. If there are no errors, i.e. the resource
227
- # was saved successfully, the response +redirect+'s to the resource
228
- # i.e. its +show+ action.
229
- # 2. If there are validation errors, the response
230
- # renders a default action, which is <tt>:new</tt> for a
231
- # +post+ request or <tt>:edit</tt> for +patch+ or +put+.
232
- # Thus an example like this -
233
- #
234
- # respond_to :html, :xml
235
- #
236
- # def create
237
- # @user = User.new(params[:user])
238
- # flash[:notice] = 'User was successfully created.' if @user.save
239
- # respond_with(@user)
240
- # end
161
+ # Provide separate templates for each format and variant:
241
162
  #
242
- # is equivalent, in the absence of <tt>create.html.erb</tt>, to -
243
- #
244
- # def create
245
- # @user = User.new(params[:user])
246
- # respond_to do |format|
247
- # if @user.save
248
- # flash[:notice] = 'User was successfully created.'
249
- # format.html { redirect_to(@user) }
250
- # format.xml { render xml: @user }
251
- # else
252
- # format.html { render action: "new" }
253
- # format.xml { render xml: @user }
254
- # end
255
- # end
256
- # end
163
+ # app/views/projects/show.html.erb
164
+ # app/views/projects/show.html+tablet.erb
165
+ # app/views/projects/show.html+phone.erb
257
166
  #
258
- # * for a javascript request - if the template isn't found, an exception is
259
- # raised.
260
- # * for other requests - i.e. data formats such as xml, json, csv etc, if
261
- # the resource passed to +respond_with+ responds to <code>to_<format></code>,
262
- # the method attempts to render the resource in the requested format
263
- # directly, e.g. for an xml request, the response is equivalent to calling
264
- # <code>render xml: resource</code>.
167
+ # When you're not sharing any code within the format, you can simplify defining variants
168
+ # using the inline syntax:
265
169
  #
266
- # === Nested resources
170
+ # respond_to do |format|
171
+ # format.js { render "trash" }
172
+ # format.html.phone { redirect_to progress_path }
173
+ # format.html.none { render "trash" }
174
+ # end
267
175
  #
268
- # As outlined above, the +resources+ argument passed to +respond_with+
269
- # can play two roles. It can be used to generate the redirect url
270
- # for successful html requests (e.g. for +create+ actions when
271
- # no template exists), while for formats other than html and javascript
272
- # it is the object that gets rendered, by being converted directly to the
273
- # required format (again assuming no template exists).
176
+ # Variants also support common `any`/`all` block that formats have.
274
177
  #
275
- # For redirecting successful html requests, +respond_with+ also supports
276
- # the use of nested resources, which are supplied in the same way as
277
- # in <code>form_for</code> and <code>polymorphic_url</code>. For example -
178
+ # It works for both inline:
278
179
  #
279
- # def create
280
- # @project = Project.find(params[:project_id])
281
- # @task = @project.comments.build(params[:task])
282
- # flash[:notice] = 'Task was successfully created.' if @task.save
283
- # respond_with(@project, @task)
180
+ # respond_to do |format|
181
+ # format.html.any { render text: "any" }
182
+ # format.html.phone { render text: "phone" }
284
183
  # end
285
184
  #
286
- # This would cause +respond_with+ to redirect to <code>project_task_url</code>
287
- # instead of <code>task_url</code>. For request formats other than html or
288
- # javascript, if multiple resources are passed in this way, it is the last
289
- # one specified that is rendered.
185
+ # and block syntax:
290
186
  #
291
- # === Customizing response behavior
187
+ # respond_to do |format|
188
+ # format.html do |variant|
189
+ # variant.any(:tablet, :phablet){ render text: "any" }
190
+ # variant.phone { render text: "phone" }
191
+ # end
192
+ # end
292
193
  #
293
- # Like +respond_to+, +respond_with+ may also be called with a block that
294
- # can be used to overwrite any of the default responses, e.g. -
194
+ # You can also set an array of variants:
295
195
  #
296
- # def create
297
- # @user = User.new(params[:user])
298
- # flash[:notice] = "User was successfully created." if @user.save
196
+ # request.variant = [:tablet, :phone]
299
197
  #
300
- # respond_with(@user) do |format|
301
- # format.html { render }
302
- # end
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:
200
+ #
201
+ # respond_to do |format|
202
+ # format.html.none
203
+ # format.html.phone # this gets rendered
303
204
  # end
304
205
  #
305
- # The argument passed to the block is an ActionController::MimeResponds::Collector
306
- # object which stores the responses for the formats defined within the
307
- # block. Note that formats with responses defined explicitly in this way
308
- # do not have to first be declared using the class method +respond_to+.
309
- #
310
- # Also, a hash passed to +respond_with+ immediately after the specified
311
- # resource(s) is interpreted as a set of options relevant to all
312
- # formats. Any option accepted by +render+ can be used, e.g.
313
- # respond_with @people, status: 200
314
- # However, note that these options are ignored after an unsuccessful attempt
315
- # to save a resource, e.g. when automatically rendering <tt>:new</tt>
316
- # after a post request.
317
- #
318
- # Two additional options are relevant specifically to +respond_with+ -
319
- # 1. <tt>:location</tt> - overwrites the default redirect location used after
320
- # a successful html +post+ request.
321
- # 2. <tt>:action</tt> - overwrites the default render action used after an
322
- # unsuccessful html +post+ request.
323
- def respond_with(*resources, &block)
324
- raise "In order to use respond_with, first you need to declare the formats your " \
325
- "controller responds to in the class level" if self.class.mimes_for_respond_to.empty?
326
-
327
- if collector = retrieve_collector_from_mimes(&block)
328
- options = resources.size == 1 ? {} : resources.extract_options!
329
- options[:default_response] = collector.response
330
- (options.delete(:responder) || self.class.responder).call(self, resources, options)
331
- end
332
- end
333
-
334
- protected
335
-
336
- # Collect mimes declared in the class method respond_to valid for the
337
- # current action.
338
- def collect_mimes_from_class_level #:nodoc:
339
- action = action_name.to_s
340
-
341
- self.class.mimes_for_respond_to.keys.select do |mime|
342
- config = self.class.mimes_for_respond_to[mime]
343
-
344
- if config[:except]
345
- !config[:except].include?(action)
346
- elsif config[:only]
347
- config[:only].include?(action)
348
- else
349
- true
350
- end
351
- end
352
- end
206
+ # Be sure to check the documentation of <tt>ActionController::MimeResponds.respond_to</tt>
207
+ # for more examples.
208
+ def respond_to(*mimes)
209
+ raise ArgumentError, "respond_to takes either types or a block, never both" if mimes.any? && block_given?
353
210
 
354
- # Returns a Collector object containing the appropriate mime-type response
355
- # for the current request, based on the available responses defined by a block.
356
- # In typical usage this is the block passed to +respond_with+ or +respond_to+.
357
- #
358
- # Sends :not_acceptable to the client and returns nil if no suitable format
359
- # is available.
360
- def retrieve_collector_from_mimes(mimes=nil, &block) #:nodoc:
361
- mimes ||= collect_mimes_from_class_level
362
- collector = Collector.new(mimes)
363
- block.call(collector) if block_given?
364
- format = collector.negotiate_format(request)
211
+ collector = Collector.new(mimes, request.variant)
212
+ yield collector if block_given?
365
213
 
366
- if format
367
- self.content_type ||= format.to_s
368
- lookup_context.formats = [format.to_sym]
369
- lookup_context.rendered_format = lookup_context.formats.first
370
- collector
214
+ if format = collector.negotiate_format(request)
215
+ _process_format(format)
216
+ response = collector.response
217
+ response ? response.call : render({})
371
218
  else
372
219
  raise ActionController::UnknownFormat
373
220
  end
@@ -376,8 +223,8 @@ module ActionController #:nodoc:
376
223
  # A container for responses available from the current controller for
377
224
  # requests for different mime-types sent to a particular action.
378
225
  #
379
- # The public controller methods +respond_with+ and +respond_to+ may be called
380
- # with a block that is used to define responses to different mime-types, e.g.
226
+ # The public controller methods +respond_to+ may be called with a block
227
+ # that is used to define responses to different mime-types, e.g.
381
228
  # for +respond_to+ :
382
229
  #
383
230
  # respond_to do |format|
@@ -397,11 +244,13 @@ module ActionController #:nodoc:
397
244
  # request, with this response then being accessible by calling #response.
398
245
  class Collector
399
246
  include AbstractController::Collector
400
- attr_accessor :order, :format
247
+ attr_accessor :format
248
+
249
+ def initialize(mimes, variant = nil)
250
+ @responses = {}
251
+ @variant = variant
401
252
 
402
- def initialize(mimes)
403
- @order, @responses = [], {}
404
- mimes.each { |mime| send(mime) }
253
+ mimes.each { |mime| @responses["Mime::#{mime.upcase}".constantize] = nil }
405
254
  end
406
255
 
407
256
  def any(*args, &block)
@@ -415,16 +264,62 @@ module ActionController #:nodoc:
415
264
 
416
265
  def custom(mime_type, &block)
417
266
  mime_type = Mime::Type.lookup(mime_type.to_s) unless mime_type.is_a?(Mime::Type)
418
- @order << mime_type
419
- @responses[mime_type] ||= block
267
+ @responses[mime_type] ||= if block_given?
268
+ block
269
+ else
270
+ VariantCollector.new(@variant)
271
+ end
420
272
  end
421
273
 
422
274
  def response
423
- @responses.fetch(format, @responses[Mime::ALL])
275
+ response = @responses.fetch(format, @responses[Mime::ALL])
276
+ if response.is_a?(VariantCollector) # `format.html.phone` - variant inline syntax
277
+ response.variant
278
+ elsif response.nil? || response.arity == 0 # `format.html` - just a format, call its block
279
+ response
280
+ else # `format.html{ |variant| variant.phone }` - variant block syntax
281
+ variant_collector = VariantCollector.new(@variant)
282
+ response.call(variant_collector) # call format block with variants collector
283
+ variant_collector.variant
284
+ end
424
285
  end
425
286
 
426
287
  def negotiate_format(request)
427
- @format = request.negotiate_mime(order)
288
+ @format = request.negotiate_mime(@responses.keys)
289
+ end
290
+
291
+ class VariantCollector #:nodoc:
292
+ def initialize(variant = nil)
293
+ @variant = variant
294
+ @variants = {}
295
+ end
296
+
297
+ def any(*args, &block)
298
+ if block_given?
299
+ if args.any? && args.none?{ |a| a == @variant }
300
+ args.each{ |v| @variants[v] = block }
301
+ else
302
+ @variants[:any] = block
303
+ end
304
+ end
305
+ end
306
+ alias :all :any
307
+
308
+ def method_missing(name, *args, &block)
309
+ @variants[name] = block if block_given?
310
+ end
311
+
312
+ def variant
313
+ if @variant.nil?
314
+ @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
+ else
320
+ @variants[:any]
321
+ end
322
+ end
428
323
  end
429
324
  end
430
325
  end
@@ -5,8 +5,8 @@ require 'active_support/core_ext/struct'
5
5
  require 'action_dispatch/http/mime_type'
6
6
 
7
7
  module ActionController
8
- # Wraps the parameters hash into a nested hash. This will allow clients to submit
9
- # POST requests without having to specify any root elements.
8
+ # Wraps the parameters hash into a nested hash. This will allow clients to
9
+ # submit requests without having to specify any root elements.
10
10
  #
11
11
  # This functionality is enabled in +config/initializers/wrap_parameters.rb+
12
12
  # and can be customized. If you are upgrading to \Rails 3.1, this file will
@@ -16,7 +16,7 @@ module ActionController
16
16
  # a non-empty array:
17
17
  #
18
18
  # class UsersController < ApplicationController
19
- # wrap_parameters format: [:json, :xml]
19
+ # wrap_parameters format: [:json, :xml, :url_encoded_form, :multipart_form]
20
20
  # end
21
21
  #
22
22
  # If you enable +ParamsWrapper+ for +:json+ format, instead of having to
@@ -231,7 +231,12 @@ module ActionController
231
231
  # by the metal call stack.
232
232
  def process_action(*args)
233
233
  if _wrapper_enabled?
234
- wrapped_hash = _wrap_parameters request.request_parameters
234
+ if request.parameters[_wrapper_key].present?
235
+ wrapped_hash = _extract_parameters(request.parameters)
236
+ else
237
+ wrapped_hash = _wrap_parameters request.request_parameters
238
+ end
239
+
235
240
  wrapped_keys = request.request_parameters.keys
236
241
  wrapped_filtered_hash = _wrap_parameters request.filtered_parameters.slice(*wrapped_keys)
237
242
 
@@ -239,7 +244,7 @@ module ActionController
239
244
  request.parameters.merge! wrapped_hash
240
245
  request.request_parameters.merge! wrapped_hash
241
246
 
242
- # This will make the wrapped hash displayed in the log file
247
+ # This will display the wrapped hash in the log file
243
248
  request.filtered_parameters.merge! wrapped_filtered_hash
244
249
  end
245
250
  super
@@ -247,7 +252,7 @@ module ActionController
247
252
 
248
253
  private
249
254
 
250
- # Returns the wrapper key which will use to stored wrapped parameters.
255
+ # Returns the wrapper key which will be used to stored wrapped parameters.
251
256
  def _wrapper_key
252
257
  _wrapper_options.name
253
258
  end
@@ -259,14 +264,16 @@ module ActionController
259
264
 
260
265
  # Returns the list of parameters which will be selected for wrapped.
261
266
  def _wrap_parameters(parameters)
262
- value = if include_only = _wrapper_options.include
267
+ { _wrapper_key => _extract_parameters(parameters) }
268
+ end
269
+
270
+ def _extract_parameters(parameters)
271
+ if include_only = _wrapper_options.include
263
272
  parameters.slice(*include_only)
264
273
  else
265
274
  exclude = _wrapper_options.exclude || []
266
275
  parameters.except(*(exclude + EXCLUDE_PARAMETERS))
267
276
  end
268
-
269
- { _wrapper_key => value }
270
277
  end
271
278
 
272
279
  # Checks if we should perform parameters wrapping.
@@ -6,7 +6,7 @@ module ActionController
6
6
  extend ActiveSupport::Concern
7
7
 
8
8
  delegate :headers, :status=, :location=, :content_type=,
9
- :status, :location, :content_type, :to => "@_response"
9
+ :status, :location, :content_type, :response_code, :to => "@_response"
10
10
 
11
11
  def dispatch(action, request)
12
12
  set_response!(request)
@@ -14,7 +14,7 @@ module ActionController
14
14
  include ActionController::RackDelegation
15
15
  include ActionController::UrlFor
16
16
 
17
- # Redirects the browser to the target specified in +options+. This parameter can take one of three forms:
17
+ # Redirects the browser to the target specified in +options+. This parameter can be any one of:
18
18
  #
19
19
  # * <tt>Hash</tt> - The URL will be generated by calling url_for with the +options+.
20
20
  # * <tt>Record</tt> - The URL will be generated by calling url_for with the +options+, which will reference a named URL for that record.
@@ -24,6 +24,8 @@ module ActionController
24
24
  # * <tt>:back</tt> - Back to the page that issued the request. Useful for forms that are triggered from multiple places.
25
25
  # Short-hand for <tt>redirect_to(request.env["HTTP_REFERER"])</tt>
26
26
  #
27
+ # === Examples:
28
+ #
27
29
  # redirect_to action: "show", id: 5
28
30
  # redirect_to post
29
31
  # redirect_to "http://www.rubyonrails.org"
@@ -32,7 +34,7 @@ module ActionController
32
34
  # redirect_to :back
33
35
  # redirect_to proc { edit_post_url(@post) }
34
36
  #
35
- # The redirection happens as a "302 Found" header unless otherwise specified.
37
+ # The redirection happens as a "302 Found" header unless otherwise specified using the <tt>:status</tt> option:
36
38
  #
37
39
  # redirect_to post_url(@post), status: :found
38
40
  # redirect_to action: 'atom', status: :moved_permanently
@@ -58,18 +60,43 @@ module ActionController
58
60
  # redirect_to post_url(@post), alert: "Watch it, mister!"
59
61
  # redirect_to post_url(@post), status: :found, notice: "Pay attention to the road"
60
62
  # redirect_to post_url(@post), status: 301, flash: { updated_post_id: @post.id }
61
- # redirect_to { action: 'atom' }, alert: "Something serious happened"
63
+ # redirect_to({ action: 'atom' }, alert: "Something serious happened")
62
64
  #
63
- # When using <tt>redirect_to :back</tt>, if there is no referrer, ActionController::RedirectBackError will be raised. You may specify some fallback
64
- # behavior for this case by rescuing ActionController::RedirectBackError.
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>.
65
69
  def redirect_to(options = {}, response_status = {}) #:doc:
66
70
  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)
67
72
  raise AbstractController::DoubleRenderError if response_body
68
73
 
69
74
  self.status = _extract_redirect_to_status(options, response_status)
70
- self.location = _compute_redirect_to_location(options)
71
- self.response_body = "<html><body>You are being <a href=\"#{ERB::Util.h(location)}\">redirected</a>.</body></html>"
75
+ self.location = _compute_redirect_to_location(request, options)
76
+ self.response_body = "<html><body>You are being <a href=\"#{ERB::Util.unwrapped_html_escape(location)}\">redirected</a>.</body></html>"
77
+ end
78
+
79
+ def _compute_redirect_to_location(request, options) #:nodoc:
80
+ case options
81
+ # The scheme name consist of a letter followed by any combination of
82
+ # letters, digits, and the plus ("+"), period ("."), or hyphen ("-")
83
+ # characters; and is terminated by a colon (":").
84
+ # See http://tools.ietf.org/html/rfc3986#section-3.1
85
+ # The protocol relative scheme starts with a double slash "//".
86
+ when /\A([a-z][a-z\d\-+\.]*:|\/\/).*/i
87
+ options
88
+ when String
89
+ request.protocol + request.host_with_port + options
90
+ when :back
91
+ request.headers["Referer"] or raise RedirectBackError
92
+ when Proc
93
+ _compute_redirect_to_location request, options.call
94
+ else
95
+ url_for(options)
96
+ end.delete("\0\r\n")
72
97
  end
98
+ module_function :_compute_redirect_to_location
99
+ public :_compute_redirect_to_location
73
100
 
74
101
  private
75
102
  def _extract_redirect_to_status(options, response_status)
@@ -81,24 +108,5 @@ module ActionController
81
108
  302
82
109
  end
83
110
  end
84
-
85
- def _compute_redirect_to_location(options)
86
- case options
87
- # The scheme name consist of a letter followed by any combination of
88
- # letters, digits, and the plus ("+"), period ("."), or hyphen ("-")
89
- # characters; and is terminated by a colon (":").
90
- # The protocol relative scheme starts with a double slash "//"
91
- when %r{\A(\w[\w+.-]*:|//).*}
92
- options
93
- when String
94
- request.protocol + request.host_with_port + options
95
- when :back
96
- request.headers["Referer"] or raise RedirectBackError
97
- when Proc
98
- _compute_redirect_to_location options.call
99
- else
100
- url_for(options)
101
- end.delete("\0\r\n")
102
- end
103
111
  end
104
112
  end