actionpack 3.2.19 → 4.2.11.3

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 (244) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +412 -503
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +11 -294
  5. data/lib/abstract_controller/asset_paths.rb +2 -2
  6. data/lib/abstract_controller/base.rb +52 -18
  7. data/lib/abstract_controller/callbacks.rb +87 -89
  8. data/lib/abstract_controller/collector.rb +17 -3
  9. data/lib/abstract_controller/helpers.rb +41 -14
  10. data/lib/abstract_controller/logger.rb +1 -2
  11. data/lib/abstract_controller/railties/routes_helpers.rb +3 -3
  12. data/lib/abstract_controller/rendering.rb +65 -118
  13. data/lib/abstract_controller/translation.rb +16 -1
  14. data/lib/abstract_controller/url_for.rb +7 -7
  15. data/lib/abstract_controller.rb +2 -10
  16. data/lib/action_controller/base.rb +61 -28
  17. data/lib/action_controller/caching/fragments.rb +30 -54
  18. data/lib/action_controller/caching.rb +38 -35
  19. data/lib/action_controller/log_subscriber.rb +35 -18
  20. data/lib/action_controller/metal/conditional_get.rb +103 -34
  21. data/lib/action_controller/metal/data_streaming.rb +20 -26
  22. data/lib/action_controller/metal/etag_with_template_digest.rb +50 -0
  23. data/lib/action_controller/metal/exceptions.rb +19 -6
  24. data/lib/action_controller/metal/flash.rb +41 -9
  25. data/lib/action_controller/metal/force_ssl.rb +70 -12
  26. data/lib/action_controller/metal/head.rb +30 -7
  27. data/lib/action_controller/metal/helpers.rb +11 -11
  28. data/lib/action_controller/metal/hide_actions.rb +0 -1
  29. data/lib/action_controller/metal/http_authentication.rb +140 -94
  30. data/lib/action_controller/metal/implicit_render.rb +1 -1
  31. data/lib/action_controller/metal/instrumentation.rb +11 -7
  32. data/lib/action_controller/metal/live.rb +328 -0
  33. data/lib/action_controller/metal/mime_responds.rb +161 -152
  34. data/lib/action_controller/metal/params_wrapper.rb +126 -81
  35. data/lib/action_controller/metal/rack_delegation.rb +10 -4
  36. data/lib/action_controller/metal/redirecting.rb +44 -41
  37. data/lib/action_controller/metal/renderers.rb +48 -19
  38. data/lib/action_controller/metal/rendering.rb +46 -11
  39. data/lib/action_controller/metal/request_forgery_protection.rb +250 -29
  40. data/lib/action_controller/metal/streaming.rb +30 -38
  41. data/lib/action_controller/metal/strong_parameters.rb +669 -0
  42. data/lib/action_controller/metal/testing.rb +12 -18
  43. data/lib/action_controller/metal/url_for.rb +31 -29
  44. data/lib/action_controller/metal.rb +31 -40
  45. data/lib/action_controller/model_naming.rb +12 -0
  46. data/lib/action_controller/railtie.rb +38 -18
  47. data/lib/action_controller/railties/helpers.rb +22 -0
  48. data/lib/action_controller/test_case.rb +359 -173
  49. data/lib/action_controller.rb +9 -16
  50. data/lib/action_dispatch/http/cache.rb +64 -11
  51. data/lib/action_dispatch/http/filter_parameters.rb +20 -10
  52. data/lib/action_dispatch/http/filter_redirect.rb +38 -0
  53. data/lib/action_dispatch/http/headers.rb +85 -17
  54. data/lib/action_dispatch/http/mime_negotiation.rb +55 -5
  55. data/lib/action_dispatch/http/mime_type.rb +167 -114
  56. data/lib/action_dispatch/http/mime_types.rb +2 -1
  57. data/lib/action_dispatch/http/parameter_filter.rb +44 -46
  58. data/lib/action_dispatch/http/parameters.rb +30 -46
  59. data/lib/action_dispatch/http/rack_cache.rb +2 -3
  60. data/lib/action_dispatch/http/request.rb +108 -45
  61. data/lib/action_dispatch/http/response.rb +247 -48
  62. data/lib/action_dispatch/http/upload.rb +60 -29
  63. data/lib/action_dispatch/http/url.rb +135 -45
  64. data/lib/action_dispatch/journey/backwards.rb +5 -0
  65. data/lib/action_dispatch/journey/formatter.rb +166 -0
  66. data/lib/action_dispatch/journey/gtg/builder.rb +162 -0
  67. data/lib/action_dispatch/journey/gtg/simulator.rb +47 -0
  68. data/lib/action_dispatch/journey/gtg/transition_table.rb +157 -0
  69. data/lib/action_dispatch/journey/nfa/builder.rb +76 -0
  70. data/lib/action_dispatch/journey/nfa/dot.rb +36 -0
  71. data/lib/action_dispatch/journey/nfa/simulator.rb +47 -0
  72. data/lib/action_dispatch/journey/nfa/transition_table.rb +163 -0
  73. data/lib/action_dispatch/journey/nodes/node.rb +128 -0
  74. data/lib/action_dispatch/journey/parser.rb +198 -0
  75. data/lib/action_dispatch/journey/parser.y +49 -0
  76. data/lib/action_dispatch/journey/parser_extras.rb +23 -0
  77. data/lib/action_dispatch/journey/path/pattern.rb +193 -0
  78. data/lib/action_dispatch/journey/route.rb +125 -0
  79. data/lib/action_dispatch/journey/router/strexp.rb +27 -0
  80. data/lib/action_dispatch/journey/router/utils.rb +93 -0
  81. data/lib/action_dispatch/journey/router.rb +144 -0
  82. data/lib/action_dispatch/journey/routes.rb +80 -0
  83. data/lib/action_dispatch/journey/scanner.rb +61 -0
  84. data/lib/action_dispatch/journey/visitors.rb +221 -0
  85. data/lib/action_dispatch/journey/visualizer/fsm.css +30 -0
  86. data/lib/action_dispatch/journey/visualizer/fsm.js +134 -0
  87. data/lib/action_dispatch/journey/visualizer/index.html.erb +52 -0
  88. data/lib/action_dispatch/journey.rb +5 -0
  89. data/lib/action_dispatch/middleware/callbacks.rb +16 -11
  90. data/lib/action_dispatch/middleware/cookies.rb +346 -125
  91. data/lib/action_dispatch/middleware/debug_exceptions.rb +52 -24
  92. data/lib/action_dispatch/middleware/exception_wrapper.rb +75 -9
  93. data/lib/action_dispatch/middleware/flash.rb +85 -72
  94. data/lib/action_dispatch/middleware/params_parser.rb +16 -31
  95. data/lib/action_dispatch/middleware/public_exceptions.rb +39 -14
  96. data/lib/action_dispatch/middleware/reloader.rb +16 -7
  97. data/lib/action_dispatch/middleware/remote_ip.rb +132 -40
  98. data/lib/action_dispatch/middleware/request_id.rb +3 -7
  99. data/lib/action_dispatch/middleware/session/abstract_store.rb +22 -20
  100. data/lib/action_dispatch/middleware/session/cache_store.rb +3 -3
  101. data/lib/action_dispatch/middleware/session/cookie_store.rb +84 -29
  102. data/lib/action_dispatch/middleware/session/mem_cache_store.rb +8 -3
  103. data/lib/action_dispatch/middleware/show_exceptions.rb +15 -44
  104. data/lib/action_dispatch/middleware/ssl.rb +72 -0
  105. data/lib/action_dispatch/middleware/stack.rb +6 -1
  106. data/lib/action_dispatch/middleware/static.rb +80 -23
  107. data/lib/action_dispatch/middleware/templates/rescues/_request_and_response.html.erb +34 -0
  108. data/lib/action_dispatch/middleware/templates/rescues/_request_and_response.text.erb +23 -0
  109. data/lib/action_dispatch/middleware/templates/rescues/_source.erb +27 -0
  110. data/lib/action_dispatch/middleware/templates/rescues/_trace.html.erb +52 -0
  111. data/lib/action_dispatch/middleware/templates/rescues/_trace.text.erb +9 -0
  112. data/lib/action_dispatch/middleware/templates/rescues/diagnostics.html.erb +16 -0
  113. data/lib/action_dispatch/middleware/templates/rescues/diagnostics.text.erb +9 -0
  114. data/lib/action_dispatch/middleware/templates/rescues/layout.erb +133 -5
  115. data/lib/action_dispatch/middleware/templates/rescues/missing_template.html.erb +11 -0
  116. data/lib/action_dispatch/middleware/templates/rescues/missing_template.text.erb +3 -0
  117. data/lib/action_dispatch/middleware/templates/rescues/routing_error.html.erb +32 -0
  118. data/lib/action_dispatch/middleware/templates/rescues/routing_error.text.erb +11 -0
  119. data/lib/action_dispatch/middleware/templates/rescues/template_error.html.erb +20 -0
  120. data/lib/action_dispatch/middleware/templates/rescues/template_error.text.erb +7 -0
  121. data/lib/action_dispatch/middleware/templates/rescues/unknown_action.html.erb +6 -0
  122. data/lib/action_dispatch/middleware/templates/rescues/unknown_action.text.erb +3 -0
  123. data/lib/action_dispatch/middleware/templates/routes/_route.html.erb +16 -0
  124. data/lib/action_dispatch/middleware/templates/routes/_table.html.erb +200 -0
  125. data/lib/action_dispatch/railtie.rb +19 -6
  126. data/lib/action_dispatch/request/session.rb +193 -0
  127. data/lib/action_dispatch/request/utils.rb +35 -0
  128. data/lib/action_dispatch/routing/endpoint.rb +10 -0
  129. data/lib/action_dispatch/routing/inspector.rb +234 -0
  130. data/lib/action_dispatch/routing/mapper.rb +897 -436
  131. data/lib/action_dispatch/routing/polymorphic_routes.rb +213 -92
  132. data/lib/action_dispatch/routing/redirection.rb +97 -37
  133. data/lib/action_dispatch/routing/route_set.rb +432 -239
  134. data/lib/action_dispatch/routing/routes_proxy.rb +7 -4
  135. data/lib/action_dispatch/routing/url_for.rb +63 -34
  136. data/lib/action_dispatch/routing.rb +57 -89
  137. data/lib/action_dispatch/testing/assertions/dom.rb +2 -36
  138. data/lib/action_dispatch/testing/assertions/response.rb +24 -38
  139. data/lib/action_dispatch/testing/assertions/routing.rb +55 -54
  140. data/lib/action_dispatch/testing/assertions/selector.rb +2 -434
  141. data/lib/action_dispatch/testing/assertions/tag.rb +2 -137
  142. data/lib/action_dispatch/testing/assertions.rb +11 -7
  143. data/lib/action_dispatch/testing/integration.rb +88 -72
  144. data/lib/action_dispatch/testing/test_process.rb +9 -6
  145. data/lib/action_dispatch/testing/test_request.rb +13 -9
  146. data/lib/action_dispatch/testing/test_response.rb +1 -5
  147. data/lib/action_dispatch.rb +24 -21
  148. data/lib/action_pack/gem_version.rb +15 -0
  149. data/lib/action_pack/version.rb +5 -7
  150. data/lib/action_pack.rb +1 -1
  151. metadata +181 -292
  152. data/lib/abstract_controller/layouts.rb +0 -423
  153. data/lib/abstract_controller/view_paths.rb +0 -96
  154. data/lib/action_controller/caching/actions.rb +0 -185
  155. data/lib/action_controller/caching/pages.rb +0 -187
  156. data/lib/action_controller/caching/sweeping.rb +0 -97
  157. data/lib/action_controller/deprecated/integration_test.rb +0 -2
  158. data/lib/action_controller/deprecated/performance_test.rb +0 -1
  159. data/lib/action_controller/deprecated.rb +0 -3
  160. data/lib/action_controller/metal/compatibility.rb +0 -65
  161. data/lib/action_controller/metal/responder.rb +0 -286
  162. data/lib/action_controller/metal/session_management.rb +0 -14
  163. data/lib/action_controller/railties/paths.rb +0 -25
  164. data/lib/action_controller/record_identifier.rb +0 -85
  165. data/lib/action_controller/vendor/html-scanner/html/document.rb +0 -68
  166. data/lib/action_controller/vendor/html-scanner/html/node.rb +0 -532
  167. data/lib/action_controller/vendor/html-scanner/html/sanitizer.rb +0 -177
  168. data/lib/action_controller/vendor/html-scanner/html/selector.rb +0 -830
  169. data/lib/action_controller/vendor/html-scanner/html/tokenizer.rb +0 -107
  170. data/lib/action_controller/vendor/html-scanner/html/version.rb +0 -11
  171. data/lib/action_controller/vendor/html-scanner.rb +0 -20
  172. data/lib/action_dispatch/middleware/best_standards_support.rb +0 -30
  173. data/lib/action_dispatch/middleware/body_proxy.rb +0 -30
  174. data/lib/action_dispatch/middleware/head.rb +0 -18
  175. data/lib/action_dispatch/middleware/rescue.rb +0 -26
  176. data/lib/action_dispatch/middleware/templates/rescues/_request_and_response.erb +0 -31
  177. data/lib/action_dispatch/middleware/templates/rescues/_trace.erb +0 -26
  178. data/lib/action_dispatch/middleware/templates/rescues/diagnostics.erb +0 -10
  179. data/lib/action_dispatch/middleware/templates/rescues/missing_template.erb +0 -2
  180. data/lib/action_dispatch/middleware/templates/rescues/routing_error.erb +0 -15
  181. data/lib/action_dispatch/middleware/templates/rescues/template_error.erb +0 -17
  182. data/lib/action_dispatch/middleware/templates/rescues/unknown_action.erb +0 -2
  183. data/lib/action_dispatch/testing/performance_test.rb +0 -10
  184. data/lib/action_view/asset_paths.rb +0 -142
  185. data/lib/action_view/base.rb +0 -220
  186. data/lib/action_view/buffers.rb +0 -43
  187. data/lib/action_view/context.rb +0 -36
  188. data/lib/action_view/flows.rb +0 -79
  189. data/lib/action_view/helpers/active_model_helper.rb +0 -50
  190. data/lib/action_view/helpers/asset_paths.rb +0 -7
  191. data/lib/action_view/helpers/asset_tag_helper.rb +0 -457
  192. data/lib/action_view/helpers/asset_tag_helpers/asset_include_tag.rb +0 -146
  193. data/lib/action_view/helpers/asset_tag_helpers/asset_paths.rb +0 -93
  194. data/lib/action_view/helpers/asset_tag_helpers/javascript_tag_helpers.rb +0 -193
  195. data/lib/action_view/helpers/asset_tag_helpers/stylesheet_tag_helpers.rb +0 -148
  196. data/lib/action_view/helpers/atom_feed_helper.rb +0 -200
  197. data/lib/action_view/helpers/cache_helper.rb +0 -64
  198. data/lib/action_view/helpers/capture_helper.rb +0 -203
  199. data/lib/action_view/helpers/controller_helper.rb +0 -25
  200. data/lib/action_view/helpers/csrf_helper.rb +0 -32
  201. data/lib/action_view/helpers/date_helper.rb +0 -1062
  202. data/lib/action_view/helpers/debug_helper.rb +0 -40
  203. data/lib/action_view/helpers/form_helper.rb +0 -1486
  204. data/lib/action_view/helpers/form_options_helper.rb +0 -658
  205. data/lib/action_view/helpers/form_tag_helper.rb +0 -685
  206. data/lib/action_view/helpers/javascript_helper.rb +0 -110
  207. data/lib/action_view/helpers/number_helper.rb +0 -622
  208. data/lib/action_view/helpers/output_safety_helper.rb +0 -38
  209. data/lib/action_view/helpers/record_tag_helper.rb +0 -111
  210. data/lib/action_view/helpers/rendering_helper.rb +0 -90
  211. data/lib/action_view/helpers/sanitize_helper.rb +0 -259
  212. data/lib/action_view/helpers/tag_helper.rb +0 -160
  213. data/lib/action_view/helpers/text_helper.rb +0 -426
  214. data/lib/action_view/helpers/translation_helper.rb +0 -91
  215. data/lib/action_view/helpers/url_helper.rb +0 -693
  216. data/lib/action_view/helpers.rb +0 -60
  217. data/lib/action_view/locale/en.yml +0 -160
  218. data/lib/action_view/log_subscriber.rb +0 -28
  219. data/lib/action_view/lookup_context.rb +0 -254
  220. data/lib/action_view/path_set.rb +0 -89
  221. data/lib/action_view/railtie.rb +0 -55
  222. data/lib/action_view/renderer/abstract_renderer.rb +0 -41
  223. data/lib/action_view/renderer/partial_renderer.rb +0 -415
  224. data/lib/action_view/renderer/renderer.rb +0 -54
  225. data/lib/action_view/renderer/streaming_template_renderer.rb +0 -106
  226. data/lib/action_view/renderer/template_renderer.rb +0 -94
  227. data/lib/action_view/template/error.rb +0 -128
  228. data/lib/action_view/template/handlers/builder.rb +0 -26
  229. data/lib/action_view/template/handlers/erb.rb +0 -125
  230. data/lib/action_view/template/handlers.rb +0 -50
  231. data/lib/action_view/template/resolver.rb +0 -272
  232. data/lib/action_view/template/text.rb +0 -30
  233. data/lib/action_view/template.rb +0 -337
  234. data/lib/action_view/test_case.rb +0 -245
  235. data/lib/action_view/testing/resolvers.rb +0 -50
  236. data/lib/action_view.rb +0 -84
  237. data/lib/sprockets/assets.rake +0 -99
  238. data/lib/sprockets/bootstrap.rb +0 -37
  239. data/lib/sprockets/compressors.rb +0 -83
  240. data/lib/sprockets/helpers/isolated_helper.rb +0 -13
  241. data/lib/sprockets/helpers/rails_helper.rb +0 -182
  242. data/lib/sprockets/helpers.rb +0 -6
  243. data/lib/sprockets/railtie.rb +0 -62
  244. data/lib/sprockets/static_compiler.rb +0 -56
@@ -1,66 +1,28 @@
1
1
  require 'abstract_controller/collector'
2
- require 'active_support/core_ext/class/attribute'
3
- require 'active_support/core_ext/object/inclusion'
4
2
 
5
3
  module ActionController #:nodoc:
6
4
  module MimeResponds
7
5
  extend ActiveSupport::Concern
8
6
 
9
- include ActionController::ImplicitRender
10
-
11
- included do
12
- class_attribute :responder, :mimes_for_respond_to
13
- self.responder = ActionController::Responder
14
- clear_respond_to
15
- end
16
-
7
+ # :stopdoc:
17
8
  module ClassMethods
18
- # Defines mime types that are rendered by default when invoking
19
- # <tt>respond_with</tt>.
20
- #
21
- # Examples:
22
- #
23
- # respond_to :html, :xml, :json
24
- #
25
- # Specifies that all actions in the controller respond to requests
26
- # for <tt>:html</tt>, <tt>:xml</tt> and <tt>:json</tt>.
27
- #
28
- # To specify on per-action basis, use <tt>:only</tt> and
29
- # <tt>:except</tt> with an array of actions or a single action:
30
- #
31
- # respond_to :html
32
- # respond_to :xml, :json, :except => [ :edit ]
33
- #
34
- # This specifies that all actions respond to <tt>:html</tt>
35
- # and all actions except <tt>:edit</tt> respond to <tt>:xml</tt> and
36
- # <tt>:json</tt>.
37
- #
38
- # respond_to :json, :only => :create
39
- #
40
- # This specifies that the <tt>:create</tt> action and no other responds
41
- # to <tt>:json</tt>.
42
- def respond_to(*mimes)
43
- options = mimes.extract_options!
44
-
45
- only_actions = Array(options.delete(:only)).map(&:to_s)
46
- except_actions = Array(options.delete(:except)).map(&:to_s)
47
-
48
- new = mimes_for_respond_to.dup
49
- mimes.each do |mime|
50
- mime = mime.to_sym
51
- new[mime] = {}
52
- new[mime][:only] = only_actions unless only_actions.empty?
53
- new[mime][:except] = except_actions unless except_actions.empty?
54
- end
55
- 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."
56
15
  end
16
+ end
57
17
 
58
- # Clear all mime types in <tt>respond_to</tt>.
59
- #
60
- def clear_respond_to
61
- self.mimes_for_respond_to = ActiveSupport::OrderedHash.new.freeze
62
- 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."
63
24
  end
25
+ # :startdoc:
64
26
 
65
27
  # Without web-service support, an action which collects the data for displaying a list of people
66
28
  # might look something like this:
@@ -76,7 +38,7 @@ module ActionController #:nodoc:
76
38
  #
77
39
  # respond_to do |format|
78
40
  # format.html
79
- # format.xml { render :xml => @people.to_xml }
41
+ # format.xml { render xml: @people }
80
42
  # end
81
43
  # end
82
44
  #
@@ -88,7 +50,7 @@ module ActionController #:nodoc:
88
50
  # (by name) if it does not already exist, without web-services, it might look like this:
89
51
  #
90
52
  # def create
91
- # @company = Company.find_or_create_by_name(params[:company][:name])
53
+ # @company = Company.find_or_create_by(name: params[:company][:name])
92
54
  # @person = @company.people.create(params[:person])
93
55
  #
94
56
  # redirect_to(person_list_url)
@@ -98,13 +60,13 @@ module ActionController #:nodoc:
98
60
  #
99
61
  # def create
100
62
  # company = params[:person].delete(:company)
101
- # @company = Company.find_or_create_by_name(company[:name])
63
+ # @company = Company.find_or_create_by(name: company[:name])
102
64
  # @person = @company.people.create(params[:person])
103
65
  #
104
66
  # respond_to do |format|
105
67
  # format.html { redirect_to(person_list_url) }
106
68
  # format.js
107
- # format.xml { render :xml => @person.to_xml(:include => @company) }
69
+ # format.xml { render xml: @person.to_xml(include: @company) }
108
70
  # end
109
71
  # end
110
72
  #
@@ -126,7 +88,7 @@ module ActionController #:nodoc:
126
88
  # Note, however, the extra bit at the top of that action:
127
89
  #
128
90
  # company = params[:person].delete(:company)
129
- # @company = Company.find_or_create_by_name(company[:name])
91
+ # @company = Company.find_or_create_by(name: company[:name])
130
92
  #
131
93
  # This is because the incoming XML document (if a web-service request is in process) can only contain a
132
94
  # single root-node. So, we have to rearrange things so that the request looks like this (url-encoded):
@@ -168,126 +130,127 @@ module ActionController #:nodoc:
168
130
  #
169
131
  # In the example above, if the format is xml, it will render:
170
132
  #
171
- # render :xml => @people
133
+ # render xml: @people
172
134
  #
173
135
  # Or if the format is json:
174
136
  #
175
- # render :json => @people
137
+ # render json: @people
138
+ #
139
+ # Formats can have different variants.
140
+ #
141
+ # The request variant is a specialization of the request format, like <tt>:tablet</tt>,
142
+ # <tt>:phone</tt>, or <tt>:desktop</tt>.
143
+ #
144
+ # We often want to render different html/json/xml templates for phones,
145
+ # tablets, and desktop browsers. Variants make it easy.
176
146
  #
177
- # Since this is a common pattern, you can use the class method respond_to
178
- # with the respond_with method to have the same results:
147
+ # You can set the variant in a +before_action+:
179
148
  #
180
- # class PeopleController < ApplicationController
181
- # respond_to :html, :xml, :json
149
+ # request.variant = :tablet if request.user_agent =~ /iPad/
182
150
  #
183
- # def index
184
- # @people = Person.all
185
- # respond_with(@people)
151
+ # Respond to variants in the action just like you respond to formats:
152
+ #
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
186
158
  # end
187
159
  # end
188
160
  #
189
- # Be sure to check respond_with and respond_to documentation for more examples.
161
+ # Provide separate templates for each format and variant:
190
162
  #
191
- def respond_to(*mimes, &block)
192
- raise ArgumentError, "respond_to takes either types or a block, never both" if mimes.any? && block_given?
193
-
194
- if collector = retrieve_collector_from_mimes(mimes, &block)
195
- response = collector.response
196
- response ? response.call : default_render({})
197
- end
198
- end
199
-
200
- # respond_with wraps a resource around a responder for default representation.
201
- # First it invokes respond_to, if a response cannot be found (ie. no block
202
- # for the request was given and template was not available), it instantiates
203
- # an ActionController::Responder with the controller and resource.
163
+ # app/views/projects/show.html.erb
164
+ # app/views/projects/show.html+tablet.erb
165
+ # app/views/projects/show.html+phone.erb
204
166
  #
205
- # ==== Example
167
+ # When you're not sharing any code within the format, you can simplify defining variants
168
+ # using the inline syntax:
206
169
  #
207
- # def index
208
- # @users = User.all
209
- # respond_with(@users)
170
+ # respond_to do |format|
171
+ # format.js { render "trash" }
172
+ # format.html.phone { redirect_to progress_path }
173
+ # format.html.none { render "trash" }
210
174
  # end
211
175
  #
212
- # It also accepts a block to be given. It's used to overwrite a default
213
- # response:
176
+ # Variants also support common `any`/`all` block that formats have.
214
177
  #
215
- # def create
216
- # @user = User.new(params[:user])
217
- # flash[:notice] = "User was successfully created." if @user.save
178
+ # It works for both inline:
179
+ #
180
+ # respond_to do |format|
181
+ # format.html.any { render text: "any" }
182
+ # format.html.phone { render text: "phone" }
183
+ # end
184
+ #
185
+ # and block syntax:
218
186
  #
219
- # respond_with(@user) do |format|
220
- # format.html { render }
187
+ # respond_to do |format|
188
+ # format.html do |variant|
189
+ # variant.any(:tablet, :phablet){ render text: "any" }
190
+ # variant.phone { render text: "phone" }
221
191
  # end
222
192
  # end
223
193
  #
224
- # All options given to respond_with are sent to the underlying responder,
225
- # except for the option :responder itself. Since the responder interface
226
- # is quite simple (it just needs to respond to call), you can even give
227
- # a proc to it.
194
+ # You can also set an array of variants:
228
195
  #
229
- # In order to use respond_with, first you need to declare the formats your
230
- # controller responds to in the class level with a call to <tt>respond_to</tt>.
196
+ # request.variant = [:tablet, :phone]
231
197
  #
232
- def respond_with(*resources, &block)
233
- raise "In order to use respond_with, first you need to declare the formats your " <<
234
- "controller responds to in the class level" if self.class.mimes_for_respond_to.empty?
235
-
236
- if collector = retrieve_collector_from_mimes(&block)
237
- options = resources.size == 1 ? {} : resources.extract_options!
238
- options[:default_response] = collector.response
239
- (options.delete(:responder) || self.class.responder).call(self, resources, options)
240
- end
241
- end
242
-
243
- protected
244
-
245
- # Collect mimes declared in the class method respond_to valid for the
246
- # current action.
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:
247
200
  #
248
- def collect_mimes_from_class_level #:nodoc:
249
- action = action_name.to_s
250
-
251
- self.class.mimes_for_respond_to.keys.select do |mime|
252
- config = self.class.mimes_for_respond_to[mime]
253
-
254
- if config[:except]
255
- !action.in?(config[:except])
256
- elsif config[:only]
257
- action.in?(config[:only])
258
- else
259
- true
260
- end
261
- end
262
- end
201
+ # respond_to do |format|
202
+ # format.html.none
203
+ # format.html.phone # this gets rendered
204
+ # end
205
+ #
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?
263
210
 
264
- # Collects mimes and return the response for the negotiated format. Returns
265
- # nil if :not_acceptable was sent to the client.
266
- #
267
- def retrieve_collector_from_mimes(mimes=nil, &block) #:nodoc:
268
- mimes ||= collect_mimes_from_class_level
269
- collector = Collector.new(mimes)
270
- block.call(collector) if block_given?
271
- format = collector.negotiate_format(request)
211
+ collector = Collector.new(mimes, request.variant)
212
+ yield collector if block_given?
272
213
 
273
- if format
274
- self.content_type ||= format.to_s
275
- lookup_context.formats = [format.to_sym]
276
- lookup_context.rendered_format = lookup_context.formats.first
277
- collector
214
+ if format = collector.negotiate_format(request)
215
+ _process_format(format)
216
+ response = collector.response
217
+ response ? response.call : render({})
278
218
  else
279
- head :not_acceptable
280
- nil
219
+ raise ActionController::UnknownFormat
281
220
  end
282
221
  end
283
222
 
284
- class Collector #:nodoc:
223
+ # A container for responses available from the current controller for
224
+ # requests for different mime-types sent to a particular action.
225
+ #
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.
228
+ # for +respond_to+ :
229
+ #
230
+ # respond_to do |format|
231
+ # format.html
232
+ # format.xml { render xml: @people }
233
+ # end
234
+ #
235
+ # In this usage, the argument passed to the block (+format+ above) is an
236
+ # instance of the ActionController::MimeResponds::Collector class. This
237
+ # object serves as a container in which available responses can be stored by
238
+ # calling any of the dynamically generated, mime-type-specific methods such
239
+ # as +html+, +xml+ etc on the Collector. Each response is represented by a
240
+ # corresponding block if present.
241
+ #
242
+ # A subsequent call to #negotiate_format(request) will enable the Collector
243
+ # to determine which specific mime-type it should respond with for the current
244
+ # request, with this response then being accessible by calling #response.
245
+ class Collector
285
246
  include AbstractController::Collector
286
- attr_accessor :order, :format
247
+ attr_accessor :format
287
248
 
288
- def initialize(mimes)
289
- @order, @responses = [], {}
290
- mimes.each { |mime| send(mime) }
249
+ def initialize(mimes, variant = nil)
250
+ @responses = {}
251
+ @variant = variant
252
+
253
+ mimes.each { |mime| @responses["Mime::#{mime.upcase}".constantize] = nil }
291
254
  end
292
255
 
293
256
  def any(*args, &block)
@@ -301,16 +264,62 @@ module ActionController #:nodoc:
301
264
 
302
265
  def custom(mime_type, &block)
303
266
  mime_type = Mime::Type.lookup(mime_type.to_s) unless mime_type.is_a?(Mime::Type)
304
- @order << mime_type
305
- @responses[mime_type] ||= block
267
+ @responses[mime_type] ||= if block_given?
268
+ block
269
+ else
270
+ VariantCollector.new(@variant)
271
+ end
306
272
  end
307
273
 
308
274
  def response
309
- @responses[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
310
285
  end
311
286
 
312
287
  def negotiate_format(request)
313
- @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
314
323
  end
315
324
  end
316
325
  end