actionpack 3.2.22.5 → 5.2.4

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 (271) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +279 -603
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +13 -297
  5. data/lib/abstract_controller/asset_paths.rb +4 -2
  6. data/lib/abstract_controller/base.rb +82 -52
  7. data/lib/abstract_controller/caching/fragments.rb +166 -0
  8. data/lib/abstract_controller/caching.rb +66 -0
  9. data/lib/abstract_controller/callbacks.rb +117 -103
  10. data/lib/abstract_controller/collector.rb +18 -7
  11. data/lib/abstract_controller/error.rb +6 -0
  12. data/lib/abstract_controller/helpers.rb +65 -38
  13. data/lib/abstract_controller/logger.rb +3 -2
  14. data/lib/abstract_controller/railties/routes_helpers.rb +5 -3
  15. data/lib/abstract_controller/rendering.rb +77 -129
  16. data/lib/abstract_controller/translation.rb +21 -3
  17. data/lib/abstract_controller/url_for.rb +9 -7
  18. data/lib/abstract_controller.rb +12 -13
  19. data/lib/action_controller/api/api_rendering.rb +16 -0
  20. data/lib/action_controller/api.rb +149 -0
  21. data/lib/action_controller/base.rb +81 -40
  22. data/lib/action_controller/caching.rb +22 -62
  23. data/lib/action_controller/form_builder.rb +50 -0
  24. data/lib/action_controller/log_subscriber.rb +30 -18
  25. data/lib/action_controller/metal/basic_implicit_render.rb +13 -0
  26. data/lib/action_controller/metal/conditional_get.rb +190 -47
  27. data/lib/action_controller/metal/content_security_policy.rb +52 -0
  28. data/lib/action_controller/metal/cookies.rb +3 -3
  29. data/lib/action_controller/metal/data_streaming.rb +40 -65
  30. data/lib/action_controller/metal/etag_with_flash.rb +18 -0
  31. data/lib/action_controller/metal/etag_with_template_digest.rb +57 -0
  32. data/lib/action_controller/metal/exceptions.rb +19 -12
  33. data/lib/action_controller/metal/flash.rb +42 -9
  34. data/lib/action_controller/metal/force_ssl.rb +79 -19
  35. data/lib/action_controller/metal/head.rb +35 -10
  36. data/lib/action_controller/metal/helpers.rb +31 -21
  37. data/lib/action_controller/metal/http_authentication.rb +182 -134
  38. data/lib/action_controller/metal/implicit_render.rb +62 -8
  39. data/lib/action_controller/metal/instrumentation.rb +28 -26
  40. data/lib/action_controller/metal/live.rb +312 -0
  41. data/lib/action_controller/metal/mime_responds.rb +159 -163
  42. data/lib/action_controller/metal/parameter_encoding.rb +51 -0
  43. data/lib/action_controller/metal/params_wrapper.rb +146 -93
  44. data/lib/action_controller/metal/redirecting.rb +80 -56
  45. data/lib/action_controller/metal/renderers.rb +119 -47
  46. data/lib/action_controller/metal/rendering.rb +89 -32
  47. data/lib/action_controller/metal/request_forgery_protection.rb +373 -41
  48. data/lib/action_controller/metal/rescue.rb +9 -16
  49. data/lib/action_controller/metal/streaming.rb +39 -45
  50. data/lib/action_controller/metal/strong_parameters.rb +1086 -0
  51. data/lib/action_controller/metal/testing.rb +8 -29
  52. data/lib/action_controller/metal/url_for.rb +43 -32
  53. data/lib/action_controller/metal.rb +112 -106
  54. data/lib/action_controller/railtie.rb +56 -18
  55. data/lib/action_controller/railties/helpers.rb +24 -0
  56. data/lib/action_controller/renderer.rb +117 -0
  57. data/lib/action_controller/template_assertions.rb +11 -0
  58. data/lib/action_controller/test_case.rb +402 -347
  59. data/lib/action_controller.rb +31 -30
  60. data/lib/action_dispatch/http/cache.rb +133 -34
  61. data/lib/action_dispatch/http/content_security_policy.rb +272 -0
  62. data/lib/action_dispatch/http/filter_parameters.rb +40 -24
  63. data/lib/action_dispatch/http/filter_redirect.rb +37 -0
  64. data/lib/action_dispatch/http/headers.rb +117 -16
  65. data/lib/action_dispatch/http/mime_negotiation.rb +98 -33
  66. data/lib/action_dispatch/http/mime_type.rb +198 -146
  67. data/lib/action_dispatch/http/mime_types.rb +22 -7
  68. data/lib/action_dispatch/http/parameter_filter.rb +61 -49
  69. data/lib/action_dispatch/http/parameters.rb +94 -51
  70. data/lib/action_dispatch/http/rack_cache.rb +4 -3
  71. data/lib/action_dispatch/http/request.rb +262 -117
  72. data/lib/action_dispatch/http/response.rb +400 -86
  73. data/lib/action_dispatch/http/upload.rb +66 -29
  74. data/lib/action_dispatch/http/url.rb +232 -60
  75. data/lib/action_dispatch/journey/formatter.rb +189 -0
  76. data/lib/action_dispatch/journey/gtg/builder.rb +164 -0
  77. data/lib/action_dispatch/journey/gtg/simulator.rb +41 -0
  78. data/lib/action_dispatch/journey/gtg/transition_table.rb +158 -0
  79. data/lib/action_dispatch/journey/nfa/builder.rb +78 -0
  80. data/lib/action_dispatch/journey/nfa/dot.rb +36 -0
  81. data/lib/action_dispatch/journey/nfa/simulator.rb +49 -0
  82. data/lib/action_dispatch/journey/nfa/transition_table.rb +120 -0
  83. data/lib/action_dispatch/journey/nodes/node.rb +140 -0
  84. data/lib/action_dispatch/journey/parser.rb +199 -0
  85. data/lib/action_dispatch/journey/parser.y +50 -0
  86. data/lib/action_dispatch/journey/parser_extras.rb +31 -0
  87. data/lib/action_dispatch/journey/path/pattern.rb +199 -0
  88. data/lib/action_dispatch/journey/route.rb +203 -0
  89. data/lib/action_dispatch/journey/router/utils.rb +102 -0
  90. data/lib/action_dispatch/journey/router.rb +156 -0
  91. data/lib/action_dispatch/journey/routes.rb +82 -0
  92. data/lib/action_dispatch/journey/scanner.rb +64 -0
  93. data/lib/action_dispatch/journey/visitors.rb +268 -0
  94. data/lib/action_dispatch/journey/visualizer/fsm.css +30 -0
  95. data/lib/action_dispatch/journey/visualizer/fsm.js +134 -0
  96. data/lib/action_dispatch/journey/visualizer/index.html.erb +52 -0
  97. data/lib/action_dispatch/journey.rb +7 -0
  98. data/lib/action_dispatch/middleware/callbacks.rb +17 -13
  99. data/lib/action_dispatch/middleware/cookies.rb +494 -162
  100. data/lib/action_dispatch/middleware/debug_exceptions.rb +176 -53
  101. data/lib/action_dispatch/middleware/debug_locks.rb +124 -0
  102. data/lib/action_dispatch/middleware/exception_wrapper.rb +103 -38
  103. data/lib/action_dispatch/middleware/executor.rb +21 -0
  104. data/lib/action_dispatch/middleware/flash.rb +128 -91
  105. data/lib/action_dispatch/middleware/public_exceptions.rb +43 -16
  106. data/lib/action_dispatch/middleware/reloader.rb +6 -83
  107. data/lib/action_dispatch/middleware/remote_ip.rb +151 -49
  108. data/lib/action_dispatch/middleware/request_id.rb +19 -15
  109. data/lib/action_dispatch/middleware/session/abstract_store.rb +38 -34
  110. data/lib/action_dispatch/middleware/session/cache_store.rb +14 -9
  111. data/lib/action_dispatch/middleware/session/cookie_store.rb +94 -44
  112. data/lib/action_dispatch/middleware/session/mem_cache_store.rb +15 -4
  113. data/lib/action_dispatch/middleware/show_exceptions.rb +36 -61
  114. data/lib/action_dispatch/middleware/ssl.rb +150 -0
  115. data/lib/action_dispatch/middleware/stack.rb +33 -41
  116. data/lib/action_dispatch/middleware/static.rb +92 -48
  117. data/lib/action_dispatch/middleware/templates/rescues/_request_and_response.html.erb +22 -0
  118. data/lib/action_dispatch/middleware/templates/rescues/_request_and_response.text.erb +23 -0
  119. data/lib/action_dispatch/middleware/templates/rescues/_source.html.erb +27 -0
  120. data/lib/action_dispatch/middleware/templates/rescues/_source.text.erb +8 -0
  121. data/lib/action_dispatch/middleware/templates/rescues/_trace.html.erb +52 -0
  122. data/lib/action_dispatch/middleware/templates/rescues/_trace.text.erb +9 -0
  123. data/lib/action_dispatch/middleware/templates/rescues/diagnostics.html.erb +16 -0
  124. data/lib/action_dispatch/middleware/templates/rescues/diagnostics.text.erb +9 -0
  125. data/lib/action_dispatch/middleware/templates/rescues/invalid_statement.html.erb +21 -0
  126. data/lib/action_dispatch/middleware/templates/rescues/invalid_statement.text.erb +13 -0
  127. data/lib/action_dispatch/middleware/templates/rescues/layout.erb +134 -5
  128. data/lib/action_dispatch/middleware/templates/rescues/missing_template.html.erb +11 -0
  129. data/lib/action_dispatch/middleware/templates/rescues/missing_template.text.erb +3 -0
  130. data/lib/action_dispatch/middleware/templates/rescues/routing_error.html.erb +32 -0
  131. data/lib/action_dispatch/middleware/templates/rescues/routing_error.text.erb +11 -0
  132. data/lib/action_dispatch/middleware/templates/rescues/template_error.html.erb +20 -0
  133. data/lib/action_dispatch/middleware/templates/rescues/template_error.text.erb +7 -0
  134. data/lib/action_dispatch/middleware/templates/rescues/unknown_action.html.erb +6 -0
  135. data/lib/action_dispatch/middleware/templates/rescues/unknown_action.text.erb +3 -0
  136. data/lib/action_dispatch/middleware/templates/routes/_route.html.erb +16 -0
  137. data/lib/action_dispatch/middleware/templates/routes/_table.html.erb +200 -0
  138. data/lib/action_dispatch/railtie.rb +29 -8
  139. data/lib/action_dispatch/request/session.rb +234 -0
  140. data/lib/action_dispatch/request/utils.rb +78 -0
  141. data/lib/action_dispatch/routing/endpoint.rb +17 -0
  142. data/lib/action_dispatch/routing/inspector.rb +225 -0
  143. data/lib/action_dispatch/routing/mapper.rb +1329 -582
  144. data/lib/action_dispatch/routing/polymorphic_routes.rb +237 -94
  145. data/lib/action_dispatch/routing/redirection.rb +120 -50
  146. data/lib/action_dispatch/routing/route_set.rb +545 -322
  147. data/lib/action_dispatch/routing/routes_proxy.rb +37 -7
  148. data/lib/action_dispatch/routing/url_for.rb +103 -34
  149. data/lib/action_dispatch/routing.rb +66 -99
  150. data/lib/action_dispatch/system_test_case.rb +147 -0
  151. data/lib/action_dispatch/system_testing/browser.rb +49 -0
  152. data/lib/action_dispatch/system_testing/driver.rb +59 -0
  153. data/lib/action_dispatch/system_testing/server.rb +31 -0
  154. data/lib/action_dispatch/system_testing/test_helpers/screenshot_helper.rb +96 -0
  155. data/lib/action_dispatch/system_testing/test_helpers/setup_and_teardown.rb +31 -0
  156. data/lib/action_dispatch/system_testing/test_helpers/undef_methods.rb +26 -0
  157. data/lib/action_dispatch/testing/assertion_response.rb +47 -0
  158. data/lib/action_dispatch/testing/assertions/response.rb +53 -42
  159. data/lib/action_dispatch/testing/assertions/routing.rb +79 -74
  160. data/lib/action_dispatch/testing/assertions.rb +15 -9
  161. data/lib/action_dispatch/testing/integration.rb +361 -207
  162. data/lib/action_dispatch/testing/request_encoder.rb +55 -0
  163. data/lib/action_dispatch/testing/test_process.rb +28 -19
  164. data/lib/action_dispatch/testing/test_request.rb +30 -33
  165. data/lib/action_dispatch/testing/test_response.rb +35 -11
  166. data/lib/action_dispatch.rb +42 -32
  167. data/lib/action_pack/gem_version.rb +17 -0
  168. data/lib/action_pack/version.rb +7 -7
  169. data/lib/action_pack.rb +4 -2
  170. metadata +116 -175
  171. data/lib/abstract_controller/layouts.rb +0 -423
  172. data/lib/abstract_controller/view_paths.rb +0 -96
  173. data/lib/action_controller/caching/actions.rb +0 -185
  174. data/lib/action_controller/caching/fragments.rb +0 -127
  175. data/lib/action_controller/caching/pages.rb +0 -187
  176. data/lib/action_controller/caching/sweeping.rb +0 -97
  177. data/lib/action_controller/deprecated/integration_test.rb +0 -2
  178. data/lib/action_controller/deprecated/performance_test.rb +0 -1
  179. data/lib/action_controller/deprecated.rb +0 -3
  180. data/lib/action_controller/metal/compatibility.rb +0 -65
  181. data/lib/action_controller/metal/hide_actions.rb +0 -41
  182. data/lib/action_controller/metal/rack_delegation.rb +0 -26
  183. data/lib/action_controller/metal/responder.rb +0 -286
  184. data/lib/action_controller/metal/session_management.rb +0 -14
  185. data/lib/action_controller/middleware.rb +0 -39
  186. data/lib/action_controller/railties/paths.rb +0 -25
  187. data/lib/action_controller/record_identifier.rb +0 -85
  188. data/lib/action_controller/vendor/html-scanner/html/document.rb +0 -68
  189. data/lib/action_controller/vendor/html-scanner/html/node.rb +0 -532
  190. data/lib/action_controller/vendor/html-scanner/html/sanitizer.rb +0 -177
  191. data/lib/action_controller/vendor/html-scanner/html/selector.rb +0 -830
  192. data/lib/action_controller/vendor/html-scanner/html/tokenizer.rb +0 -107
  193. data/lib/action_controller/vendor/html-scanner/html/version.rb +0 -11
  194. data/lib/action_controller/vendor/html-scanner.rb +0 -20
  195. data/lib/action_dispatch/middleware/best_standards_support.rb +0 -30
  196. data/lib/action_dispatch/middleware/body_proxy.rb +0 -30
  197. data/lib/action_dispatch/middleware/head.rb +0 -18
  198. data/lib/action_dispatch/middleware/params_parser.rb +0 -75
  199. data/lib/action_dispatch/middleware/rescue.rb +0 -26
  200. data/lib/action_dispatch/middleware/templates/rescues/_request_and_response.erb +0 -31
  201. data/lib/action_dispatch/middleware/templates/rescues/_trace.erb +0 -26
  202. data/lib/action_dispatch/middleware/templates/rescues/diagnostics.erb +0 -10
  203. data/lib/action_dispatch/middleware/templates/rescues/missing_template.erb +0 -2
  204. data/lib/action_dispatch/middleware/templates/rescues/routing_error.erb +0 -15
  205. data/lib/action_dispatch/middleware/templates/rescues/template_error.erb +0 -17
  206. data/lib/action_dispatch/middleware/templates/rescues/unknown_action.erb +0 -2
  207. data/lib/action_dispatch/testing/assertions/dom.rb +0 -37
  208. data/lib/action_dispatch/testing/assertions/selector.rb +0 -435
  209. data/lib/action_dispatch/testing/assertions/tag.rb +0 -138
  210. data/lib/action_dispatch/testing/performance_test.rb +0 -10
  211. data/lib/action_view/asset_paths.rb +0 -142
  212. data/lib/action_view/base.rb +0 -220
  213. data/lib/action_view/buffers.rb +0 -43
  214. data/lib/action_view/context.rb +0 -36
  215. data/lib/action_view/flows.rb +0 -79
  216. data/lib/action_view/helpers/active_model_helper.rb +0 -50
  217. data/lib/action_view/helpers/asset_paths.rb +0 -7
  218. data/lib/action_view/helpers/asset_tag_helper.rb +0 -457
  219. data/lib/action_view/helpers/asset_tag_helpers/asset_include_tag.rb +0 -146
  220. data/lib/action_view/helpers/asset_tag_helpers/asset_paths.rb +0 -93
  221. data/lib/action_view/helpers/asset_tag_helpers/javascript_tag_helpers.rb +0 -193
  222. data/lib/action_view/helpers/asset_tag_helpers/stylesheet_tag_helpers.rb +0 -148
  223. data/lib/action_view/helpers/atom_feed_helper.rb +0 -200
  224. data/lib/action_view/helpers/cache_helper.rb +0 -64
  225. data/lib/action_view/helpers/capture_helper.rb +0 -203
  226. data/lib/action_view/helpers/controller_helper.rb +0 -25
  227. data/lib/action_view/helpers/csrf_helper.rb +0 -32
  228. data/lib/action_view/helpers/date_helper.rb +0 -1062
  229. data/lib/action_view/helpers/debug_helper.rb +0 -40
  230. data/lib/action_view/helpers/form_helper.rb +0 -1486
  231. data/lib/action_view/helpers/form_options_helper.rb +0 -658
  232. data/lib/action_view/helpers/form_tag_helper.rb +0 -685
  233. data/lib/action_view/helpers/javascript_helper.rb +0 -110
  234. data/lib/action_view/helpers/number_helper.rb +0 -622
  235. data/lib/action_view/helpers/output_safety_helper.rb +0 -38
  236. data/lib/action_view/helpers/record_tag_helper.rb +0 -111
  237. data/lib/action_view/helpers/rendering_helper.rb +0 -92
  238. data/lib/action_view/helpers/sanitize_helper.rb +0 -259
  239. data/lib/action_view/helpers/tag_helper.rb +0 -167
  240. data/lib/action_view/helpers/text_helper.rb +0 -426
  241. data/lib/action_view/helpers/translation_helper.rb +0 -91
  242. data/lib/action_view/helpers/url_helper.rb +0 -693
  243. data/lib/action_view/helpers.rb +0 -60
  244. data/lib/action_view/locale/en.yml +0 -160
  245. data/lib/action_view/log_subscriber.rb +0 -28
  246. data/lib/action_view/lookup_context.rb +0 -258
  247. data/lib/action_view/path_set.rb +0 -101
  248. data/lib/action_view/railtie.rb +0 -55
  249. data/lib/action_view/renderer/abstract_renderer.rb +0 -41
  250. data/lib/action_view/renderer/partial_renderer.rb +0 -415
  251. data/lib/action_view/renderer/renderer.rb +0 -61
  252. data/lib/action_view/renderer/streaming_template_renderer.rb +0 -106
  253. data/lib/action_view/renderer/template_renderer.rb +0 -95
  254. data/lib/action_view/template/error.rb +0 -128
  255. data/lib/action_view/template/handlers/builder.rb +0 -26
  256. data/lib/action_view/template/handlers/erb.rb +0 -125
  257. data/lib/action_view/template/handlers.rb +0 -50
  258. data/lib/action_view/template/resolver.rb +0 -298
  259. data/lib/action_view/template/text.rb +0 -30
  260. data/lib/action_view/template.rb +0 -337
  261. data/lib/action_view/test_case.rb +0 -246
  262. data/lib/action_view/testing/resolvers.rb +0 -49
  263. data/lib/action_view.rb +0 -84
  264. data/lib/sprockets/assets.rake +0 -99
  265. data/lib/sprockets/bootstrap.rb +0 -37
  266. data/lib/sprockets/compressors.rb +0 -83
  267. data/lib/sprockets/helpers/isolated_helper.rb +0 -13
  268. data/lib/sprockets/helpers/rails_helper.rb +0 -182
  269. data/lib/sprockets/helpers.rb +0 -6
  270. data/lib/sprockets/railtie.rb +0 -62
  271. data/lib/sprockets/static_compiler.rb +0 -56
@@ -1,415 +0,0 @@
1
- require 'active_support/core_ext/object/blank'
2
-
3
- module ActionView
4
- # = Action View Partials
5
- #
6
- # There's also a convenience method for rendering sub templates within the current controller that depends on a
7
- # single object (we call this kind of sub templates for partials). It relies on the fact that partials should
8
- # follow the naming convention of being prefixed with an underscore -- as to separate them from regular
9
- # templates that could be rendered on their own.
10
- #
11
- # In a template for Advertiser#account:
12
- #
13
- # <%= render :partial => "account" %>
14
- #
15
- # This would render "advertiser/_account.html.erb".
16
- #
17
- # In another template for Advertiser#buy, we could have:
18
- #
19
- # <%= render :partial => "account", :locals => { :account => @buyer } %>
20
- #
21
- # <% @advertisements.each do |ad| %>
22
- # <%= render :partial => "ad", :locals => { :ad => ad } %>
23
- # <% end %>
24
- #
25
- # This would first render "advertiser/_account.html.erb" with @buyer passed in as the local variable +account+, then
26
- # render "advertiser/_ad.html.erb" and pass the local variable +ad+ to the template for display.
27
- #
28
- # == The :as and :object options
29
- #
30
- # By default <tt>ActionView::PartialRenderer</tt> doesn't have any local variables.
31
- # The <tt>:object</tt> option can be used to pass an object to the partial. For instance:
32
- #
33
- # <%= render :partial => "account", :object => @buyer %>
34
- #
35
- # would provide the +@buyer+ object to the partial, available under the local variable +account+ and is
36
- # equivalent to:
37
- #
38
- # <%= render :partial => "account", :locals => { :account => @buyer } %>
39
- #
40
- # With the <tt>:as</tt> option we can specify a different name for said local variable. For example, if we
41
- # wanted it to be +user+ instead of +account+ we'd do:
42
- #
43
- # <%= render :partial => "account", :object => @buyer, :as => 'user' %>
44
- #
45
- # This is equivalent to
46
- #
47
- # <%= render :partial => "account", :locals => { :user => @buyer } %>
48
- #
49
- # == Rendering a collection of partials
50
- #
51
- # The example of partial use describes a familiar pattern where a template needs to iterate over an array and
52
- # render a sub template for each of the elements. This pattern has been implemented as a single method that
53
- # accepts an array and renders a partial by the same name as the elements contained within. So the three-lined
54
- # example in "Using partials" can be rewritten with a single line:
55
- #
56
- # <%= render :partial => "ad", :collection => @advertisements %>
57
- #
58
- # This will render "advertiser/_ad.html.erb" and pass the local variable +ad+ to the template for display. An
59
- # iteration counter will automatically be made available to the template with a name of the form
60
- # +partial_name_counter+. In the case of the example above, the template would be fed +ad_counter+.
61
- #
62
- # The <tt>:as</tt> option may be used when rendering partials.
63
- #
64
- # You can specify a partial to be rendered between elements via the <tt>:spacer_template</tt> option.
65
- # The following example will render <tt>advertiser/_ad_divider.html.erb</tt> between each ad partial:
66
- #
67
- # <%= render :partial => "ad", :collection => @advertisements, :spacer_template => "ad_divider" %>
68
- #
69
- # If the given <tt>:collection</tt> is nil or empty, <tt>render</tt> will return nil. This will allow you
70
- # to specify a text which will displayed instead by using this form:
71
- #
72
- # <%= render(:partial => "ad", :collection => @advertisements) || "There's no ad to be displayed" %>
73
- #
74
- # NOTE: Due to backwards compatibility concerns, the collection can't be one of hashes. Normally you'd also
75
- # just keep domain objects, like Active Records, in there.
76
- #
77
- # == Rendering shared partials
78
- #
79
- # Two controllers can share a set of partials and render them like this:
80
- #
81
- # <%= render :partial => "advertisement/ad", :locals => { :ad => @advertisement } %>
82
- #
83
- # This will render the partial "advertisement/_ad.html.erb" regardless of which controller this is being called from.
84
- #
85
- # == Rendering objects that respond to `to_partial_path`
86
- #
87
- # Instead of explicitly naming the location of a partial, you can also let PartialRenderer do the work
88
- # and pick the proper path by checking `to_proper_path` method. If the object passed to render is a collection,
89
- # all objects must return the same path.
90
- #
91
- # # @account.to_partial_path returns 'accounts/account', so it can be used to replace:
92
- # # <%= render :partial => "accounts/account", :locals => { :account => @account} %>
93
- # <%= render :partial => @account %>
94
- #
95
- # # @posts is an array of Post instances, so every post record returns 'posts/post' on `to_partial_path`,
96
- # # that's why we can replace:
97
- # # <%= render :partial => "posts/post", :collection => @posts %>
98
- # <%= render :partial => @posts %>
99
- #
100
- # == Rendering the default case
101
- #
102
- # If you're not going to be using any of the options like collections or layouts, you can also use the short-hand
103
- # defaults of render to render partials. Examples:
104
- #
105
- # # Instead of <%= render :partial => "account" %>
106
- # <%= render "account" %>
107
- #
108
- # # Instead of <%= render :partial => "account", :locals => { :account => @buyer } %>
109
- # <%= render "account", :account => @buyer %>
110
- #
111
- # # @account.to_partial_path returns 'accounts/account', so it can be used to replace:
112
- # # <%= render :partial => "accounts/account", :locals => { :account => @account} %>
113
- # <%= render @account %>
114
- #
115
- # # @posts is an array of Post instances, so every post record returns 'posts/post' on `to_partial_path`,
116
- # # that's why we can replace:
117
- # # <%= render :partial => "posts/post", :collection => @posts %>
118
- # <%= render @posts %>
119
- #
120
- # == Rendering partials with layouts
121
- #
122
- # Partials can have their own layouts applied to them. These layouts are different than the ones that are
123
- # specified globally for the entire action, but they work in a similar fashion. Imagine a list with two types
124
- # of users:
125
- #
126
- # <%# app/views/users/index.html.erb &>
127
- # Here's the administrator:
128
- # <%= render :partial => "user", :layout => "administrator", :locals => { :user => administrator } %>
129
- #
130
- # Here's the editor:
131
- # <%= render :partial => "user", :layout => "editor", :locals => { :user => editor } %>
132
- #
133
- # <%# app/views/users/_user.html.erb &>
134
- # Name: <%= user.name %>
135
- #
136
- # <%# app/views/users/_administrator.html.erb &>
137
- # <div id="administrator">
138
- # Budget: $<%= user.budget %>
139
- # <%= yield %>
140
- # </div>
141
- #
142
- # <%# app/views/users/_editor.html.erb &>
143
- # <div id="editor">
144
- # Deadline: <%= user.deadline %>
145
- # <%= yield %>
146
- # </div>
147
- #
148
- # ...this will return:
149
- #
150
- # Here's the administrator:
151
- # <div id="administrator">
152
- # Budget: $<%= user.budget %>
153
- # Name: <%= user.name %>
154
- # </div>
155
- #
156
- # Here's the editor:
157
- # <div id="editor">
158
- # Deadline: <%= user.deadline %>
159
- # Name: <%= user.name %>
160
- # </div>
161
- #
162
- # You can also apply a layout to a block within any template:
163
- #
164
- # <%# app/views/users/_chief.html.erb &>
165
- # <%= render(:layout => "administrator", :locals => { :user => chief }) do %>
166
- # Title: <%= chief.title %>
167
- # <% end %>
168
- #
169
- # ...this will return:
170
- #
171
- # <div id="administrator">
172
- # Budget: $<%= user.budget %>
173
- # Title: <%= chief.name %>
174
- # </div>
175
- #
176
- # As you can see, the <tt>:locals</tt> hash is shared between both the partial and its layout.
177
- #
178
- # If you pass arguments to "yield" then this will be passed to the block. One way to use this is to pass
179
- # an array to layout and treat it as an enumerable.
180
- #
181
- # <%# app/views/users/_user.html.erb &>
182
- # <div class="user">
183
- # Budget: $<%= user.budget %>
184
- # <%= yield user %>
185
- # </div>
186
- #
187
- # <%# app/views/users/index.html.erb &>
188
- # <%= render :layout => @users do |user| %>
189
- # Title: <%= user.title %>
190
- # <% end %>
191
- #
192
- # This will render the layout for each user and yield to the block, passing the user, each time.
193
- #
194
- # You can also yield multiple times in one layout and use block arguments to differentiate the sections.
195
- #
196
- # <%# app/views/users/_user.html.erb &>
197
- # <div class="user">
198
- # <%= yield user, :header %>
199
- # Budget: $<%= user.budget %>
200
- # <%= yield user, :footer %>
201
- # </div>
202
- #
203
- # <%# app/views/users/index.html.erb &>
204
- # <%= render :layout => @users do |user, section| %>
205
- # <%- case section when :header -%>
206
- # Title: <%= user.title %>
207
- # <%- when :footer -%>
208
- # Deadline: <%= user.deadline %>
209
- # <%- end -%>
210
- # <% end %>
211
- class PartialRenderer < AbstractRenderer
212
- PARTIAL_NAMES = Hash.new { |h,k| h[k] = {} }
213
-
214
- def initialize(*)
215
- super
216
- @context_prefix = @lookup_context.prefixes.first
217
- @partial_names = PARTIAL_NAMES[@context_prefix]
218
- end
219
-
220
- def render(context, options, block)
221
- setup(context, options, block)
222
- identifier = (@template = find_partial) ? @template.identifier : @path
223
-
224
- @lookup_context.rendered_format ||= begin
225
- if @template && @template.formats.present?
226
- @template.formats.first
227
- else
228
- formats.first
229
- end
230
- end
231
-
232
- if @collection
233
- instrument(:collection, :identifier => identifier || "collection", :count => @collection.size) do
234
- render_collection
235
- end
236
- else
237
- instrument(:partial, :identifier => identifier) do
238
- render_partial
239
- end
240
- end
241
- end
242
-
243
- def render_collection
244
- return nil if @collection.blank?
245
-
246
- if @options.key?(:spacer_template)
247
- spacer = find_template(@options[:spacer_template]).render(@view, @locals)
248
- end
249
-
250
- result = @template ? collection_with_template : collection_without_template
251
- result.join(spacer).html_safe
252
- end
253
-
254
- def render_partial
255
- locals, view, block = @locals, @view, @block
256
- object, as = @object, @variable
257
-
258
- if !block && (layout = @options[:layout])
259
- layout = find_template(layout.to_s)
260
- end
261
-
262
- object ||= locals[as]
263
- locals[as] = object
264
-
265
- content = @template.render(view, locals) do |*name|
266
- view._layout_for(*name, &block)
267
- end
268
-
269
- content = layout.render(view, locals){ content } if layout
270
- content
271
- end
272
-
273
- private
274
-
275
- def setup(context, options, block)
276
- @view = context
277
- partial = options[:partial]
278
-
279
- @options = options
280
- @locals = options[:locals] || {}
281
- @block = block
282
- @details = extract_details(options)
283
-
284
- if String === partial
285
- @object = options[:object]
286
- @path = partial
287
- @collection = collection
288
- else
289
- @object = partial
290
-
291
- if @collection = collection_from_object || collection
292
- paths = @collection_data = @collection.map { |o| partial_path(o) }
293
- @path = paths.uniq.size == 1 ? paths.first : nil
294
- else
295
- @path = partial_path
296
- end
297
- end
298
-
299
- if @path
300
- @variable, @variable_counter = retrieve_variable(@path)
301
- else
302
- paths.map! { |path| retrieve_variable(path).unshift(path) }
303
- end
304
-
305
- if String === partial && @variable.to_s !~ /^[a-z_][a-zA-Z_0-9]*$/
306
- raise ArgumentError.new("The partial name (#{partial}) is not a valid Ruby identifier; " +
307
- "make sure your partial name starts with a letter or underscore, " +
308
- "and is followed by any combinations of letters, numbers, or underscores.")
309
- end
310
-
311
- extract_format(@path, @details)
312
- self
313
- end
314
-
315
- def collection
316
- if @options.key?(:collection)
317
- collection = @options[:collection]
318
- collection.respond_to?(:to_ary) ? collection.to_ary : []
319
- end
320
- end
321
-
322
- def collection_from_object
323
- if @object.respond_to?(:to_ary)
324
- @object.to_ary
325
- end
326
- end
327
-
328
- def find_partial
329
- if path = @path
330
- locals = @locals.keys
331
- locals << @variable
332
- locals << @variable_counter if @collection
333
- find_template(path, locals)
334
- end
335
- end
336
-
337
- def find_template(path=@path, locals=@locals.keys)
338
- prefixes = path.include?(?/) ? [] : @lookup_context.prefixes
339
- @lookup_context.find_template(path, prefixes, true, locals, @details)
340
- end
341
-
342
- def collection_with_template
343
- segments, locals, template = [], @locals, @template
344
- as, counter = @variable, @variable_counter
345
-
346
- locals[counter] = -1
347
-
348
- @collection.each do |object|
349
- locals[counter] += 1
350
- locals[as] = object
351
- segments << template.render(@view, locals)
352
- end
353
-
354
- segments
355
- end
356
-
357
- def collection_without_template
358
- segments, locals, collection_data = [], @locals, @collection_data
359
- index, template, cache = -1, nil, {}
360
- keys = @locals.keys
361
-
362
- @collection.each_with_index do |object, i|
363
- path, *data = collection_data[i]
364
- template = (cache[path] ||= find_template(path, keys + data))
365
- locals[data[0]] = object
366
- locals[data[1]] = (index += 1)
367
- segments << template.render(@view, locals)
368
- end
369
-
370
- @template = template
371
- segments
372
- end
373
-
374
- def partial_path(object = @object)
375
- object = object.to_model if object.respond_to?(:to_model)
376
-
377
- path = if object.respond_to?(:to_partial_path)
378
- object.to_partial_path
379
- else
380
- klass = object.class
381
- if klass.respond_to?(:model_name)
382
- ActiveSupport::Deprecation.warn "ActiveModel-compatible objects whose classes return a #model_name that responds to #partial_path are deprecated. Please respond to #to_partial_path directly instead."
383
- klass.model_name.partial_path
384
- else
385
- raise ArgumentError.new("'#{object.inspect}' is not an ActiveModel-compatible object that returns a valid partial path.")
386
- end
387
- end
388
-
389
- @partial_names[path] ||= merge_prefix_into_object_path(@context_prefix, path.dup)
390
- end
391
-
392
- def merge_prefix_into_object_path(prefix, object_path)
393
- if prefix.include?(?/) && object_path.include?(?/)
394
- prefixes = []
395
- prefix_array = File.dirname(prefix).split('/')
396
- object_path_array = object_path.split('/')[0..-3] # skip model dir & partial
397
-
398
- prefix_array.each_with_index do |dir, index|
399
- break if dir == object_path_array[index]
400
- prefixes << dir
401
- end
402
-
403
- (prefixes << object_path).join("/")
404
- else
405
- object_path
406
- end
407
- end
408
-
409
- def retrieve_variable(path)
410
- variable = @options.fetch(:as) { path[%r'_?(\w+)(\.\w+)*$', 1] }.try(:to_sym)
411
- variable_counter = :"#{variable}_counter" if @collection
412
- [variable, variable_counter]
413
- end
414
- end
415
- end
@@ -1,61 +0,0 @@
1
- require 'active_support/hash_with_indifferent_access'
2
-
3
- module ActionView
4
- # This is the main entry point for rendering. It basically delegates
5
- # to other objects like TemplateRenderer and PartialRenderer which
6
- # actually renders the template.
7
- class Renderer
8
- attr_accessor :lookup_context
9
-
10
- def initialize(lookup_context)
11
- @lookup_context = lookup_context
12
- end
13
-
14
- # Main render entry point shared by AV and AC.
15
- def render(context, options)
16
- if (options.is_a?(HashWithIndifferentAccess) && !options.respond_to?(:permitted?)) ||
17
- (options.respond_to?(:permitted?) && !options.permitted?)
18
- raise ArgumentError, "render parameters are not permitted"
19
- end
20
-
21
- if options.key?(:partial)
22
- render_partial(context, options)
23
- else
24
- render_template(context, options)
25
- end
26
- end
27
-
28
- # Render but returns a valid Rack body. If fibers are defined, we return
29
- # a streaming body that renders the template piece by piece.
30
- #
31
- # Note that partials are not supported to be rendered with streaming,
32
- # so in such cases, we just wrap them in an array.
33
- def render_body(context, options)
34
- if options.key?(:partial)
35
- [render_partial(context, options)]
36
- else
37
- StreamingTemplateRenderer.new(@lookup_context).render(context, options)
38
- end
39
- end
40
-
41
- # Direct accessor to template rendering.
42
- def render_template(context, options) #:nodoc:
43
- _template_renderer.render(context, options)
44
- end
45
-
46
- # Direct access to partial rendering.
47
- def render_partial(context, options, &block) #:nodoc:
48
- _partial_renderer.render(context, options, block)
49
- end
50
-
51
- private
52
-
53
- def _template_renderer #:nodoc:
54
- @_template_renderer ||= TemplateRenderer.new(@lookup_context)
55
- end
56
-
57
- def _partial_renderer #:nodoc:
58
- @_partial_renderer ||= PartialRenderer.new(@lookup_context)
59
- end
60
- end
61
- end
@@ -1,106 +0,0 @@
1
- # 1.9 ships with Fibers but we need to require the extra
2
- # methods explicitly. We only load those extra methods if
3
- # Fiber is available in the first place.
4
- require 'fiber' if defined?(Fiber)
5
-
6
- module ActionView
7
- # == TODO
8
- #
9
- # * Support streaming from child templates, partials and so on.
10
- # * Integrate exceptions with exceptron
11
- # * Rack::Cache needs to support streaming bodies
12
- class StreamingTemplateRenderer < TemplateRenderer #:nodoc:
13
- # A valid Rack::Body (i.e. it responds to each).
14
- # It is initialized with a block that, when called, starts
15
- # rendering the template.
16
- class Body #:nodoc:
17
- def initialize(&start)
18
- @start = start
19
- end
20
-
21
- def each(&block)
22
- begin
23
- @start.call(block)
24
- rescue Exception => exception
25
- log_error(exception)
26
- block.call ActionView::Base.streaming_completion_on_exception
27
- end
28
- self
29
- end
30
-
31
- private
32
-
33
- # This is the same logging logic as in ShowExceptions middleware.
34
- # TODO Once "exceptron" is in, refactor this piece to simply re-use exceptron.
35
- def log_error(exception) #:nodoc:
36
- logger = ActionController::Base.logger
37
- return unless logger
38
-
39
- message = "\n#{exception.class} (#{exception.message}):\n"
40
- message << exception.annoted_source_code.to_s if exception.respond_to?(:annoted_source_code)
41
- message << " " << exception.backtrace.join("\n ")
42
- logger.fatal("#{message}\n\n")
43
- end
44
- end
45
-
46
- # For streaming, instead of rendering a given a template, we return a Body
47
- # object that responds to each. This object is initialized with a block
48
- # that knows how to render the template.
49
- def render_template(template, layout_name = nil, locals = {}) #:nodoc:
50
- return [super] unless layout_name && template.supports_streaming?
51
-
52
- locals ||= {}
53
- layout = layout_name && find_layout(layout_name, locals.keys)
54
-
55
- Body.new do |buffer|
56
- delayed_render(buffer, template, layout, @view, locals)
57
- end
58
- end
59
-
60
- private
61
-
62
- def delayed_render(buffer, template, layout, view, locals)
63
- # Wrap the given buffer in the StreamingBuffer and pass it to the
64
- # underlying template handler. Now, everytime something is concatenated
65
- # to the buffer, it is not appended to an array, but streamed straight
66
- # to the client.
67
- output = ActionView::StreamingBuffer.new(buffer)
68
- yielder = lambda { |*name| view._layout_for(*name) }
69
-
70
- instrument(:template, :identifier => template.identifier, :layout => layout.try(:virtual_path)) do
71
- fiber = Fiber.new do
72
- if layout
73
- layout.render(view, locals, output, &yielder)
74
- else
75
- # If you don't have a layout, just render the thing
76
- # and concatenate the final result. This is the same
77
- # as a layout with just <%= yield %>
78
- output.safe_concat view._layout_for
79
- end
80
- end
81
-
82
- # Set the view flow to support streaming. It will be aware
83
- # when to stop rendering the layout because it needs to search
84
- # something in the template and vice-versa.
85
- view.view_flow = StreamingFlow.new(view, fiber)
86
-
87
- # Yo! Start the fiber!
88
- fiber.resume
89
-
90
- # If the fiber is still alive, it means we need something
91
- # from the template, so start rendering it. If not, it means
92
- # the layout exited without requiring anything from the template.
93
- if fiber.alive?
94
- content = template.render(view, locals, &yielder)
95
-
96
- # Once rendering the template is done, sets its content in the :layout key.
97
- view.view_flow.set(:layout, content)
98
-
99
- # In case the layout continues yielding, we need to resume
100
- # the fiber until all yields are handled.
101
- fiber.resume while fiber.alive?
102
- end
103
- end
104
- end
105
- end
106
- end
@@ -1,95 +0,0 @@
1
- require 'active_support/core_ext/object/try'
2
- require 'active_support/core_ext/array/wrap'
3
-
4
- module ActionView
5
- class TemplateRenderer < AbstractRenderer #:nodoc:
6
- def render(context, options)
7
- @view = context
8
- @details = extract_details(options)
9
- extract_format(options[:file] || options[:template], @details)
10
- template = determine_template(options)
11
- context = @lookup_context
12
-
13
- unless context.rendered_format
14
- context.formats = template.formats unless template.formats.empty?
15
- context.rendered_format = context.formats.first
16
- end
17
-
18
- render_template(template, options[:layout], options[:locals])
19
- end
20
-
21
- # Determine the template to be rendered using the given options.
22
- def determine_template(options) #:nodoc:
23
- keys = options[:locals].try(:keys) || []
24
- if options.key?(:text)
25
- Template::Text.new(options[:text], formats.try(:first))
26
- elsif options.key?(:app_template_file)
27
- find_template(options[:app_template_file], nil, false, keys, @details)
28
- elsif options.key?(:file)
29
- with_fallbacks { find_file(options[:file], nil, false, keys, @details) }
30
- elsif options.key?(:inline)
31
- handler = Template.handler_for_extension(options[:type] || "erb")
32
- Template.new(options[:inline], "inline template", handler, :locals => keys)
33
- elsif options.key?(:template)
34
- options[:template].respond_to?(:render) ?
35
- options[:template] : find_template(options[:template], options[:prefixes], false, keys, @details)
36
- else
37
- raise ArgumentError, "You invoked render but did not give any of :partial, :template, :inline, :file or :text option."
38
- end
39
- end
40
-
41
- # Renders the given template. An string representing the layout can be
42
- # supplied as well.
43
- def render_template(template, layout_name = nil, locals = {}) #:nodoc:
44
- view, locals = @view, locals || {}
45
-
46
- render_with_layout(layout_name, locals) do |layout|
47
- instrument(:template, :identifier => template.identifier, :layout => layout.try(:virtual_path)) do
48
- template.render(view, locals) { |*name| view._layout_for(*name) }
49
- end
50
- end
51
- end
52
-
53
- def render_with_layout(path, locals) #:nodoc:
54
- layout = path && find_layout(path, locals.keys)
55
- content = yield(layout)
56
-
57
- if layout
58
- view = @view
59
- view.view_flow.set(:layout, content)
60
- layout.render(view, locals){ |*name| view._layout_for(*name) }
61
- else
62
- content
63
- end
64
- end
65
-
66
- # This is the method which actually finds the layout using details in the lookup
67
- # context object. If no layout is found, it checks if at least a layout with
68
- # the given name exists across all details before raising the error.
69
- def find_layout(layout, keys)
70
- with_layout_format { resolve_layout(layout, keys) }
71
- end
72
-
73
- def resolve_layout(layout, keys)
74
- case layout
75
- when String
76
- begin
77
- if layout =~ /^\//
78
- with_fallbacks { find_template(layout, nil, false, keys, @details) }
79
- else
80
- find_template(layout, nil, false, keys, @details)
81
- end
82
- rescue ActionView::MissingTemplate
83
- all_details = @details.merge(:formats => @lookup_context.default_formats)
84
- raise unless template_exists?(layout, nil, false, keys, all_details)
85
- end
86
- when Proc
87
- resolve_layout(layout.call, keys)
88
- when FalseClass
89
- nil
90
- else
91
- layout
92
- end
93
- end
94
- end
95
- end