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,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,54 +0,0 @@
1
- module ActionView
2
- # This is the main entry point for rendering. It basically delegates
3
- # to other objects like TemplateRenderer and PartialRenderer which
4
- # actually renders the template.
5
- class Renderer
6
- attr_accessor :lookup_context
7
-
8
- def initialize(lookup_context)
9
- @lookup_context = lookup_context
10
- end
11
-
12
- # Main render entry point shared by AV and AC.
13
- def render(context, options)
14
- if options.key?(:partial)
15
- render_partial(context, options)
16
- else
17
- render_template(context, options)
18
- end
19
- end
20
-
21
- # Render but returns a valid Rack body. If fibers are defined, we return
22
- # a streaming body that renders the template piece by piece.
23
- #
24
- # Note that partials are not supported to be rendered with streaming,
25
- # so in such cases, we just wrap them in an array.
26
- def render_body(context, options)
27
- if options.key?(:partial)
28
- [render_partial(context, options)]
29
- else
30
- StreamingTemplateRenderer.new(@lookup_context).render(context, options)
31
- end
32
- end
33
-
34
- # Direct accessor to template rendering.
35
- def render_template(context, options) #:nodoc:
36
- _template_renderer.render(context, options)
37
- end
38
-
39
- # Direct access to partial rendering.
40
- def render_partial(context, options, &block) #:nodoc:
41
- _partial_renderer.render(context, options, block)
42
- end
43
-
44
- private
45
-
46
- def _template_renderer #:nodoc:
47
- @_template_renderer ||= TemplateRenderer.new(@lookup_context)
48
- end
49
-
50
- def _partial_renderer #:nodoc:
51
- @_partial_renderer ||= PartialRenderer.new(@lookup_context)
52
- end
53
- end
54
- 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,94 +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
-
25
- if options.key?(:text)
26
- Template::Text.new(options[:text], formats.try(:first))
27
- elsif options.key?(:file)
28
- with_fallbacks { find_template(options[:file], nil, false, keys, @details) }
29
- elsif options.key?(:inline)
30
- handler = Template.handler_for_extension(options[:type] || "erb")
31
- Template.new(options[:inline], "inline template", handler, :locals => keys)
32
- elsif options.key?(:template)
33
- options[:template].respond_to?(:render) ?
34
- options[:template] : find_template(options[:template], options[:prefixes], false, keys, @details)
35
- else
36
- raise ArgumentError, "You invoked render but did not give any of :partial, :template, :inline, :file or :text option."
37
- end
38
- end
39
-
40
- # Renders the given template. An string representing the layout can be
41
- # supplied as well.
42
- def render_template(template, layout_name = nil, locals = {}) #:nodoc:
43
- view, locals = @view, locals || {}
44
-
45
- render_with_layout(layout_name, locals) do |layout|
46
- instrument(:template, :identifier => template.identifier, :layout => layout.try(:virtual_path)) do
47
- template.render(view, locals) { |*name| view._layout_for(*name) }
48
- end
49
- end
50
- end
51
-
52
- def render_with_layout(path, locals) #:nodoc:
53
- layout = path && find_layout(path, locals.keys)
54
- content = yield(layout)
55
-
56
- if layout
57
- view = @view
58
- view.view_flow.set(:layout, content)
59
- layout.render(view, locals){ |*name| view._layout_for(*name) }
60
- else
61
- content
62
- end
63
- end
64
-
65
- # This is the method which actually finds the layout using details in the lookup
66
- # context object. If no layout is found, it checks if at least a layout with
67
- # the given name exists across all details before raising the error.
68
- def find_layout(layout, keys)
69
- with_layout_format { resolve_layout(layout, keys) }
70
- end
71
-
72
- def resolve_layout(layout, keys)
73
- case layout
74
- when String
75
- begin
76
- if layout =~ /^\//
77
- with_fallbacks { find_template(layout, nil, false, keys, @details) }
78
- else
79
- find_template(layout, nil, false, keys, @details)
80
- end
81
- rescue ActionView::MissingTemplate
82
- all_details = @details.merge(:formats => @lookup_context.default_formats)
83
- raise unless template_exists?(layout, nil, false, keys, all_details)
84
- end
85
- when Proc
86
- resolve_layout(layout.call, keys)
87
- when FalseClass
88
- nil
89
- else
90
- layout
91
- end
92
- end
93
- end
94
- end