actionview 4.2.11.1 → 6.1.5
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of actionview might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/CHANGELOG.md +232 -186
- data/MIT-LICENSE +1 -2
- data/README.rdoc +9 -8
- data/lib/action_view/base.rb +115 -39
- data/lib/action_view/buffers.rb +18 -1
- data/lib/action_view/cache_expiry.rb +52 -0
- data/lib/action_view/context.rb +8 -12
- data/lib/action_view/dependency_tracker.rb +61 -21
- data/lib/action_view/digestor.rb +89 -85
- data/lib/action_view/flows.rb +11 -12
- data/lib/action_view/gem_version.rb +6 -4
- data/lib/action_view/helpers/active_model_helper.rb +16 -11
- data/lib/action_view/helpers/asset_tag_helper.rb +282 -83
- data/lib/action_view/helpers/asset_url_helper.rb +175 -69
- data/lib/action_view/helpers/atom_feed_helper.rb +20 -17
- data/lib/action_view/helpers/cache_helper.rb +107 -43
- data/lib/action_view/helpers/capture_helper.rb +20 -13
- data/lib/action_view/helpers/controller_helper.rb +15 -4
- data/lib/action_view/helpers/csp_helper.rb +26 -0
- data/lib/action_view/helpers/csrf_helper.rb +8 -6
- data/lib/action_view/helpers/date_helper.rb +232 -130
- data/lib/action_view/helpers/debug_helper.rb +7 -6
- data/lib/action_view/helpers/form_helper.rb +808 -146
- data/lib/action_view/helpers/form_options_helper.rb +124 -78
- data/lib/action_view/helpers/form_tag_helper.rb +120 -74
- data/lib/action_view/helpers/javascript_helper.rb +33 -17
- data/lib/action_view/helpers/number_helper.rb +87 -62
- data/lib/action_view/helpers/output_safety_helper.rb +36 -4
- data/lib/action_view/helpers/rendering_helper.rb +21 -10
- data/lib/action_view/helpers/sanitize_helper.rb +30 -31
- data/lib/action_view/helpers/tag_helper.rb +269 -68
- data/lib/action_view/helpers/tags/base.rb +141 -97
- data/lib/action_view/helpers/tags/check_box.rb +20 -19
- data/lib/action_view/helpers/tags/checkable.rb +4 -2
- data/lib/action_view/helpers/tags/collection_check_boxes.rb +12 -34
- data/lib/action_view/helpers/tags/collection_helpers.rb +69 -36
- data/lib/action_view/helpers/tags/collection_radio_buttons.rb +6 -12
- data/lib/action_view/helpers/tags/collection_select.rb +4 -2
- data/lib/action_view/helpers/tags/color_field.rb +4 -3
- data/lib/action_view/helpers/tags/date_field.rb +3 -2
- data/lib/action_view/helpers/tags/date_select.rb +38 -37
- data/lib/action_view/helpers/tags/datetime_field.rb +4 -3
- data/lib/action_view/helpers/tags/datetime_local_field.rb +3 -2
- data/lib/action_view/helpers/tags/datetime_select.rb +2 -0
- data/lib/action_view/helpers/tags/email_field.rb +2 -0
- data/lib/action_view/helpers/tags/file_field.rb +2 -0
- data/lib/action_view/helpers/tags/grouped_collection_select.rb +4 -2
- data/lib/action_view/helpers/tags/hidden_field.rb +6 -0
- data/lib/action_view/helpers/tags/label.rb +7 -2
- data/lib/action_view/helpers/tags/month_field.rb +3 -2
- data/lib/action_view/helpers/tags/number_field.rb +2 -0
- data/lib/action_view/helpers/tags/password_field.rb +3 -1
- data/lib/action_view/helpers/tags/placeholderable.rb +3 -1
- data/lib/action_view/helpers/tags/radio_button.rb +7 -6
- data/lib/action_view/helpers/tags/range_field.rb +2 -0
- data/lib/action_view/helpers/tags/search_field.rb +14 -9
- data/lib/action_view/helpers/tags/select.rb +11 -10
- data/lib/action_view/helpers/tags/tel_field.rb +2 -0
- data/lib/action_view/helpers/tags/text_area.rb +4 -2
- data/lib/action_view/helpers/tags/text_field.rb +8 -8
- data/lib/action_view/helpers/tags/time_field.rb +3 -2
- data/lib/action_view/helpers/tags/time_select.rb +2 -0
- data/lib/action_view/helpers/tags/time_zone_select.rb +3 -1
- data/lib/action_view/helpers/tags/translator.rb +15 -16
- data/lib/action_view/helpers/tags/url_field.rb +2 -0
- data/lib/action_view/helpers/tags/week_field.rb +3 -2
- data/lib/action_view/helpers/tags.rb +3 -1
- data/lib/action_view/helpers/text_helper.rb +56 -38
- data/lib/action_view/helpers/translation_helper.rb +150 -68
- data/lib/action_view/helpers/url_helper.rb +284 -117
- data/lib/action_view/helpers.rb +5 -3
- data/lib/action_view/layouts.rb +68 -63
- data/lib/action_view/log_subscriber.rb +77 -10
- data/lib/action_view/lookup_context.rb +134 -91
- data/lib/action_view/model_naming.rb +3 -1
- data/lib/action_view/path_set.rb +26 -24
- data/lib/action_view/railtie.rb +62 -13
- data/lib/action_view/record_identifier.rb +53 -26
- data/lib/action_view/renderer/abstract_renderer.rb +151 -14
- data/lib/action_view/renderer/collection_renderer.rb +196 -0
- data/lib/action_view/renderer/object_renderer.rb +34 -0
- data/lib/action_view/renderer/partial_renderer/collection_caching.rb +102 -0
- data/lib/action_view/renderer/partial_renderer.rb +55 -303
- data/lib/action_view/renderer/renderer.rb +66 -9
- data/lib/action_view/renderer/streaming_template_renderer.rb +58 -54
- data/lib/action_view/renderer/template_renderer.rb +82 -73
- data/lib/action_view/rendering.rb +71 -45
- data/lib/action_view/routing_url_for.rb +34 -23
- data/lib/action_view/tasks/cache_digests.rake +25 -0
- data/lib/action_view/template/error.rb +44 -29
- data/lib/action_view/template/handlers/builder.rb +12 -13
- data/lib/action_view/template/handlers/erb/erubi.rb +89 -0
- data/lib/action_view/template/handlers/erb.rb +23 -89
- data/lib/action_view/template/handlers/html.rb +11 -0
- data/lib/action_view/template/handlers/raw.rb +4 -4
- data/lib/action_view/template/handlers.rb +12 -8
- data/lib/action_view/template/html.rb +10 -11
- data/lib/action_view/template/inline.rb +22 -0
- data/lib/action_view/template/raw_file.rb +25 -0
- data/lib/action_view/template/renderable.rb +24 -0
- data/lib/action_view/template/resolver.rb +263 -197
- data/lib/action_view/template/sources/file.rb +17 -0
- data/lib/action_view/template/sources.rb +13 -0
- data/lib/action_view/template/text.rb +8 -10
- data/lib/action_view/template/types.rb +18 -18
- data/lib/action_view/template.rb +108 -92
- data/lib/action_view/test_case.rb +66 -53
- data/lib/action_view/testing/resolvers.rb +24 -33
- data/lib/action_view/unbound_template.rb +31 -0
- data/lib/action_view/version.rb +3 -1
- data/lib/action_view/view_paths.rb +73 -58
- data/lib/action_view.rb +14 -8
- data/lib/assets/compiled/rails-ujs.js +746 -0
- metadata +42 -29
- data/lib/action_view/helpers/record_tag_helper.rb +0 -108
- data/lib/action_view/tasks/dependencies.rake +0 -23
@@ -1,33 +1,8 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
2
|
|
3
|
-
|
4
|
-
class PartialIteration
|
5
|
-
# The number of iterations that will be done by the partial.
|
6
|
-
attr_reader :size
|
7
|
-
|
8
|
-
# The current iteration of the partial.
|
9
|
-
attr_reader :index
|
10
|
-
|
11
|
-
def initialize(size)
|
12
|
-
@size = size
|
13
|
-
@index = 0
|
14
|
-
end
|
15
|
-
|
16
|
-
# Check if this is the first iteration of the partial.
|
17
|
-
def first?
|
18
|
-
index == 0
|
19
|
-
end
|
20
|
-
|
21
|
-
# Check if this is the last iteration of the partial.
|
22
|
-
def last?
|
23
|
-
index == size - 1
|
24
|
-
end
|
25
|
-
|
26
|
-
def iterate! # :nodoc:
|
27
|
-
@index += 1
|
28
|
-
end
|
29
|
-
end
|
3
|
+
require "action_view/renderer/partial_renderer/collection_caching"
|
30
4
|
|
5
|
+
module ActionView
|
31
6
|
# = Action View Partials
|
32
7
|
#
|
33
8
|
# There's also a convenience method for rendering sub templates within the current controller that depends on a
|
@@ -49,12 +24,12 @@ module ActionView
|
|
49
24
|
# <%= render partial: "ad", locals: { ad: ad } %>
|
50
25
|
# <% end %>
|
51
26
|
#
|
52
|
-
# This would first render
|
53
|
-
# render
|
27
|
+
# This would first render <tt>advertiser/_account.html.erb</tt> with <tt>@buyer</tt> passed in as the local variable +account+, then
|
28
|
+
# render <tt>advertiser/_ad.html.erb</tt> and pass the local variable +ad+ to the template for display.
|
54
29
|
#
|
55
30
|
# == The :as and :object options
|
56
31
|
#
|
57
|
-
# By default
|
32
|
+
# By default ActionView::PartialRenderer doesn't have any local variables.
|
58
33
|
# The <tt>:object</tt> option can be used to pass an object to the partial. For instance:
|
59
34
|
#
|
60
35
|
# <%= render partial: "account", object: @buyer %>
|
@@ -73,7 +48,7 @@ module ActionView
|
|
73
48
|
#
|
74
49
|
# <%= render partial: "account", locals: { user: @buyer } %>
|
75
50
|
#
|
76
|
-
# == Rendering a collection of partials
|
51
|
+
# == \Rendering a collection of partials
|
77
52
|
#
|
78
53
|
# The example of partial use describes a familiar pattern where a template needs to iterate over an array and
|
79
54
|
# render a sub template for each of the elements. This pattern has been implemented as a single method that
|
@@ -82,7 +57,7 @@ module ActionView
|
|
82
57
|
#
|
83
58
|
# <%= render partial: "ad", collection: @advertisements %>
|
84
59
|
#
|
85
|
-
# This will render
|
60
|
+
# This will render <tt>advertiser/_ad.html.erb</tt> and pass the local variable +ad+ to the template for display. An
|
86
61
|
# iteration object will automatically be made available to the template with a name of the form
|
87
62
|
# +partial_name_iteration+. The iteration object has knowledge about which index the current object has in
|
88
63
|
# the collection and the total size of the collection. The iteration object also has two convenience methods,
|
@@ -97,37 +72,34 @@ module ActionView
|
|
97
72
|
#
|
98
73
|
# <%= render partial: "ad", collection: @advertisements, spacer_template: "ad_divider" %>
|
99
74
|
#
|
100
|
-
# If the given <tt>:collection</tt> is nil or empty, <tt>render</tt> will return nil
|
101
|
-
# to specify a text which will displayed instead by using this form:
|
75
|
+
# If the given <tt>:collection</tt> is +nil+ or empty, <tt>render</tt> will return +nil+. This will allow you
|
76
|
+
# to specify a text which will be displayed instead by using this form:
|
102
77
|
#
|
103
78
|
# <%= render(partial: "ad", collection: @advertisements) || "There's no ad to be displayed" %>
|
104
79
|
#
|
105
|
-
#
|
106
|
-
# just keep domain objects, like Active Records, in there.
|
107
|
-
#
|
108
|
-
# == Rendering shared partials
|
80
|
+
# == \Rendering shared partials
|
109
81
|
#
|
110
82
|
# Two controllers can share a set of partials and render them like this:
|
111
83
|
#
|
112
84
|
# <%= render partial: "advertisement/ad", locals: { ad: @advertisement } %>
|
113
85
|
#
|
114
|
-
# This will render the partial
|
86
|
+
# This will render the partial <tt>advertisement/_ad.html.erb</tt> regardless of which controller this is being called from.
|
115
87
|
#
|
116
|
-
# == Rendering objects that respond to
|
88
|
+
# == \Rendering objects that respond to +to_partial_path+
|
117
89
|
#
|
118
90
|
# Instead of explicitly naming the location of a partial, you can also let PartialRenderer do the work
|
119
|
-
# and pick the proper path by checking
|
91
|
+
# and pick the proper path by checking +to_partial_path+ method.
|
120
92
|
#
|
121
93
|
# # @account.to_partial_path returns 'accounts/account', so it can be used to replace:
|
122
94
|
# # <%= render partial: "accounts/account", locals: { account: @account} %>
|
123
95
|
# <%= render partial: @account %>
|
124
96
|
#
|
125
|
-
# # @posts is an array of Post instances, so every post record returns 'posts/post' on
|
97
|
+
# # @posts is an array of Post instances, so every post record returns 'posts/post' on +to_partial_path+,
|
126
98
|
# # that's why we can replace:
|
127
99
|
# # <%= render partial: "posts/post", collection: @posts %>
|
128
100
|
# <%= render partial: @posts %>
|
129
101
|
#
|
130
|
-
# == Rendering the default case
|
102
|
+
# == \Rendering the default case
|
131
103
|
#
|
132
104
|
# If you're not going to be using any of the options like collections or layouts, you can also use the short-hand
|
133
105
|
# defaults of render to render partials. Examples:
|
@@ -142,34 +114,34 @@ module ActionView
|
|
142
114
|
# # <%= render partial: "accounts/account", locals: { account: @account} %>
|
143
115
|
# <%= render @account %>
|
144
116
|
#
|
145
|
-
# # @posts is an array of Post instances, so every post record returns 'posts/post' on
|
117
|
+
# # @posts is an array of Post instances, so every post record returns 'posts/post' on +to_partial_path+,
|
146
118
|
# # that's why we can replace:
|
147
119
|
# # <%= render partial: "posts/post", collection: @posts %>
|
148
120
|
# <%= render @posts %>
|
149
121
|
#
|
150
|
-
# == Rendering partials with layouts
|
122
|
+
# == \Rendering partials with layouts
|
151
123
|
#
|
152
124
|
# Partials can have their own layouts applied to them. These layouts are different than the ones that are
|
153
125
|
# specified globally for the entire action, but they work in a similar fashion. Imagine a list with two types
|
154
126
|
# of users:
|
155
127
|
#
|
156
|
-
# <%# app/views/users/index.html.erb
|
128
|
+
# <%# app/views/users/index.html.erb %>
|
157
129
|
# Here's the administrator:
|
158
130
|
# <%= render partial: "user", layout: "administrator", locals: { user: administrator } %>
|
159
131
|
#
|
160
132
|
# Here's the editor:
|
161
133
|
# <%= render partial: "user", layout: "editor", locals: { user: editor } %>
|
162
134
|
#
|
163
|
-
# <%# app/views/users/_user.html.erb
|
135
|
+
# <%# app/views/users/_user.html.erb %>
|
164
136
|
# Name: <%= user.name %>
|
165
137
|
#
|
166
|
-
# <%# app/views/users/_administrator.html.erb
|
138
|
+
# <%# app/views/users/_administrator.html.erb %>
|
167
139
|
# <div id="administrator">
|
168
140
|
# Budget: $<%= user.budget %>
|
169
141
|
# <%= yield %>
|
170
142
|
# </div>
|
171
143
|
#
|
172
|
-
# <%# app/views/users/_editor.html.erb
|
144
|
+
# <%# app/views/users/_editor.html.erb %>
|
173
145
|
# <div id="editor">
|
174
146
|
# Deadline: <%= user.deadline %>
|
175
147
|
# <%= yield %>
|
@@ -232,7 +204,7 @@ module ActionView
|
|
232
204
|
#
|
233
205
|
# You can also apply a layout to a block within any template:
|
234
206
|
#
|
235
|
-
# <%# app/views/users/_chief.html.erb
|
207
|
+
# <%# app/views/users/_chief.html.erb %>
|
236
208
|
# <%= render(layout: "administrator", locals: { user: chief }) do %>
|
237
209
|
# Title: <%= chief.title %>
|
238
210
|
# <% end %>
|
@@ -249,13 +221,13 @@ module ActionView
|
|
249
221
|
# If you pass arguments to "yield" then this will be passed to the block. One way to use this is to pass
|
250
222
|
# an array to layout and treat it as an enumerable.
|
251
223
|
#
|
252
|
-
# <%# app/views/users/_user.html.erb
|
224
|
+
# <%# app/views/users/_user.html.erb %>
|
253
225
|
# <div class="user">
|
254
226
|
# Budget: $<%= user.budget %>
|
255
227
|
# <%= yield user %>
|
256
228
|
# </div>
|
257
229
|
#
|
258
|
-
# <%# app/views/users/index.html.erb
|
230
|
+
# <%# app/views/users/index.html.erb %>
|
259
231
|
# <%= render layout: @users do |user| %>
|
260
232
|
# Title: <%= user.title %>
|
261
233
|
# <% end %>
|
@@ -264,14 +236,14 @@ module ActionView
|
|
264
236
|
#
|
265
237
|
# You can also yield multiple times in one layout and use block arguments to differentiate the sections.
|
266
238
|
#
|
267
|
-
# <%# app/views/users/_user.html.erb
|
239
|
+
# <%# app/views/users/_user.html.erb %>
|
268
240
|
# <div class="user">
|
269
241
|
# <%= yield user, :header %>
|
270
242
|
# Budget: $<%= user.budget %>
|
271
243
|
# <%= yield user, :footer %>
|
272
244
|
# </div>
|
273
245
|
#
|
274
|
-
# <%# app/views/users/index.html.erb
|
246
|
+
# <%# app/views/users/index.html.erb %>
|
275
247
|
# <%= render layout: @users do |user, section| %>
|
276
248
|
# <%- case section when :header -%>
|
277
249
|
# Title: <%= user.title %>
|
@@ -280,269 +252,49 @@ module ActionView
|
|
280
252
|
# <%- end -%>
|
281
253
|
# <% end %>
|
282
254
|
class PartialRenderer < AbstractRenderer
|
283
|
-
|
284
|
-
h[k] = ThreadSafe::Cache.new
|
285
|
-
end
|
286
|
-
|
287
|
-
def initialize(*)
|
288
|
-
super
|
289
|
-
@context_prefix = @lookup_context.prefixes.first
|
290
|
-
end
|
291
|
-
|
292
|
-
def render(context, options, block)
|
293
|
-
setup(context, options, block)
|
294
|
-
identifier = (@template = find_partial) ? @template.identifier : @path
|
295
|
-
|
296
|
-
@lookup_context.rendered_format ||= begin
|
297
|
-
if @template && @template.formats.present?
|
298
|
-
@template.formats.first
|
299
|
-
else
|
300
|
-
formats.first
|
301
|
-
end
|
302
|
-
end
|
255
|
+
include CollectionCaching
|
303
256
|
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
|
308
|
-
|
309
|
-
instrument(:partial, :identifier => identifier) do
|
310
|
-
render_partial
|
311
|
-
end
|
312
|
-
end
|
313
|
-
end
|
314
|
-
|
315
|
-
private
|
316
|
-
|
317
|
-
def render_collection
|
318
|
-
return nil if @collection.blank?
|
319
|
-
|
320
|
-
if @options.key?(:spacer_template)
|
321
|
-
spacer = find_template(@options[:spacer_template], @locals.keys).render(@view, @locals)
|
322
|
-
end
|
323
|
-
|
324
|
-
result = @template ? collection_with_template : collection_without_template
|
325
|
-
result.join(spacer).html_safe
|
257
|
+
def initialize(lookup_context, options)
|
258
|
+
super(lookup_context)
|
259
|
+
@options = options
|
260
|
+
@locals = @options[:locals] || {}
|
261
|
+
@details = extract_details(@options)
|
326
262
|
end
|
327
263
|
|
328
|
-
def
|
329
|
-
|
330
|
-
object, as = @object, @variable
|
264
|
+
def render(partial, context, block)
|
265
|
+
template = find_template(partial, template_keys(partial))
|
331
266
|
|
332
267
|
if !block && (layout = @options[:layout])
|
333
|
-
layout = find_template(layout.to_s,
|
268
|
+
layout = find_template(layout.to_s, template_keys(partial))
|
334
269
|
end
|
335
270
|
|
336
|
-
|
337
|
-
locals[as] = object
|
338
|
-
|
339
|
-
content = @template.render(view, locals) do |*name|
|
340
|
-
view._layout_for(*name, &block)
|
341
|
-
end
|
342
|
-
|
343
|
-
content = layout.render(view, locals){ content } if layout
|
344
|
-
content
|
271
|
+
render_partial_template(context, @locals, template, layout, block)
|
345
272
|
end
|
346
273
|
|
347
274
|
private
|
348
|
-
|
349
|
-
|
350
|
-
# finds the options and details and extracts them. The method also contains
|
351
|
-
# logic that handles the type of object passed in as the partial.
|
352
|
-
#
|
353
|
-
# If +options[:partial]+ is a string, then the +@path+ instance variable is
|
354
|
-
# set to that string. Otherwise, the +options[:partial]+ object must
|
355
|
-
# respond to +to_partial_path+ in order to setup the path.
|
356
|
-
def setup(context, options, block)
|
357
|
-
@view = context
|
358
|
-
@options = options
|
359
|
-
@block = block
|
360
|
-
|
361
|
-
@locals = options[:locals] || {}
|
362
|
-
@details = extract_details(options)
|
363
|
-
|
364
|
-
prepend_formats(options[:formats])
|
365
|
-
|
366
|
-
partial = options[:partial]
|
367
|
-
|
368
|
-
if String === partial
|
369
|
-
@has_object = options.key?(:object)
|
370
|
-
@object = options[:object]
|
371
|
-
@collection = collection_from_options
|
372
|
-
@path = partial
|
373
|
-
else
|
374
|
-
@has_object = true
|
375
|
-
@object = partial
|
376
|
-
@collection = collection_from_object || collection_from_options
|
377
|
-
|
378
|
-
if @collection
|
379
|
-
paths = @collection_data = @collection.map { |o| partial_path(o) }
|
380
|
-
@path = paths.uniq.one? ? paths.first : nil
|
381
|
-
else
|
382
|
-
@path = partial_path
|
383
|
-
end
|
384
|
-
end
|
385
|
-
|
386
|
-
if as = options[:as]
|
387
|
-
raise_invalid_option_as(as) unless as.to_s =~ /\A[a-z_]\w*\z/
|
388
|
-
as = as.to_sym
|
275
|
+
def template_keys(_)
|
276
|
+
@locals.keys
|
389
277
|
end
|
390
278
|
|
391
|
-
|
392
|
-
|
393
|
-
|
394
|
-
|
395
|
-
|
396
|
-
|
397
|
-
|
398
|
-
|
399
|
-
|
400
|
-
|
401
|
-
|
402
|
-
|
403
|
-
|
404
|
-
collection.respond_to?(:to_ary) ? collection.to_ary : []
|
405
|
-
end
|
406
|
-
end
|
407
|
-
|
408
|
-
def collection_from_object
|
409
|
-
@object.to_ary if @object.respond_to?(:to_ary)
|
410
|
-
end
|
411
|
-
|
412
|
-
def find_partial
|
413
|
-
find_template(@path, @template_keys) if @path
|
414
|
-
end
|
415
|
-
|
416
|
-
def find_template(path, locals)
|
417
|
-
prefixes = path.include?(?/) ? [] : @lookup_context.prefixes
|
418
|
-
@lookup_context.find_template(path, prefixes, true, locals, @details)
|
419
|
-
end
|
420
|
-
|
421
|
-
def collection_with_template
|
422
|
-
view, locals, template = @view, @locals, @template
|
423
|
-
as, counter, iteration = @variable, @variable_counter, @variable_iteration
|
424
|
-
|
425
|
-
if layout = @options[:layout]
|
426
|
-
layout = find_template(layout, @template_keys)
|
427
|
-
end
|
428
|
-
|
429
|
-
partial_iteration = PartialIteration.new(@collection.size)
|
430
|
-
locals[iteration] = partial_iteration
|
431
|
-
|
432
|
-
@collection.map do |object|
|
433
|
-
locals[as] = object
|
434
|
-
locals[counter] = partial_iteration.index
|
435
|
-
|
436
|
-
content = template.render(view, locals)
|
437
|
-
content = layout.render(view, locals) { content } if layout
|
438
|
-
partial_iteration.iterate!
|
439
|
-
content
|
440
|
-
end
|
441
|
-
end
|
442
|
-
|
443
|
-
def collection_without_template
|
444
|
-
view, locals, collection_data = @view, @locals, @collection_data
|
445
|
-
cache = {}
|
446
|
-
keys = @locals.keys
|
447
|
-
|
448
|
-
partial_iteration = PartialIteration.new(@collection.size)
|
449
|
-
|
450
|
-
@collection.map do |object|
|
451
|
-
index = partial_iteration.index
|
452
|
-
path, as, counter, iteration = collection_data[index]
|
453
|
-
|
454
|
-
locals[as] = object
|
455
|
-
locals[counter] = index
|
456
|
-
locals[iteration] = partial_iteration
|
457
|
-
|
458
|
-
template = (cache[path] ||= find_template(path, keys + [as, counter]))
|
459
|
-
content = template.render(view, locals)
|
460
|
-
partial_iteration.iterate!
|
461
|
-
content
|
462
|
-
end
|
463
|
-
end
|
464
|
-
|
465
|
-
# Obtains the path to where the object's partial is located. If the object
|
466
|
-
# responds to +to_partial_path+, then +to_partial_path+ will be called and
|
467
|
-
# will provide the path. If the object does not respond to +to_partial_path+,
|
468
|
-
# then an +ArgumentError+ is raised.
|
469
|
-
#
|
470
|
-
# If +prefix_partial_path_with_controller_namespace+ is true, then this
|
471
|
-
# method will prefix the partial paths with a namespace.
|
472
|
-
def partial_path(object = @object)
|
473
|
-
object = object.to_model if object.respond_to?(:to_model)
|
474
|
-
|
475
|
-
path = if object.respond_to?(:to_partial_path)
|
476
|
-
object.to_partial_path
|
477
|
-
else
|
478
|
-
raise ArgumentError.new("'#{object.inspect}' is not an ActiveModel-compatible object. It must implement :to_partial_path.")
|
479
|
-
end
|
480
|
-
|
481
|
-
if @view.prefix_partial_path_with_controller_namespace
|
482
|
-
prefixed_partial_names[path] ||= merge_prefix_into_object_path(@context_prefix, path.dup)
|
483
|
-
else
|
484
|
-
path
|
485
|
-
end
|
486
|
-
end
|
487
|
-
|
488
|
-
def prefixed_partial_names
|
489
|
-
@prefixed_partial_names ||= PREFIXED_PARTIAL_NAMES[@context_prefix]
|
490
|
-
end
|
491
|
-
|
492
|
-
def merge_prefix_into_object_path(prefix, object_path)
|
493
|
-
if prefix.include?(?/) && object_path.include?(?/)
|
494
|
-
prefixes = []
|
495
|
-
prefix_array = File.dirname(prefix).split('/')
|
496
|
-
object_path_array = object_path.split('/')[0..-3] # skip model dir & partial
|
497
|
-
|
498
|
-
prefix_array.each_with_index do |dir, index|
|
499
|
-
break if dir == object_path_array[index]
|
500
|
-
prefixes << dir
|
279
|
+
def render_partial_template(view, locals, template, layout, block)
|
280
|
+
ActiveSupport::Notifications.instrument(
|
281
|
+
"render_partial.action_view",
|
282
|
+
identifier: template.identifier,
|
283
|
+
layout: layout && layout.virtual_path
|
284
|
+
) do |payload|
|
285
|
+
content = template.render(view, locals, add_to_stack: !block) do |*name|
|
286
|
+
view._layout_for(*name, &block)
|
287
|
+
end
|
288
|
+
|
289
|
+
content = layout.render(view, locals) { content } if layout
|
290
|
+
payload[:cache_hit] = view.view_renderer.cache_hits[template.virtual_path]
|
291
|
+
build_rendered_template(content, template)
|
501
292
|
end
|
502
|
-
|
503
|
-
(prefixes << object_path).join("/")
|
504
|
-
else
|
505
|
-
object_path
|
506
293
|
end
|
507
|
-
end
|
508
|
-
|
509
|
-
def retrieve_template_keys
|
510
|
-
keys = @locals.keys
|
511
|
-
keys << @variable if @has_object || @collection
|
512
|
-
if @collection
|
513
|
-
keys << @variable_counter
|
514
|
-
keys << @variable_iteration
|
515
|
-
end
|
516
|
-
keys
|
517
|
-
end
|
518
294
|
|
519
|
-
|
520
|
-
|
521
|
-
|
522
|
-
raise_invalid_identifier(path) unless base =~ /\A_?([a-z]\w*)(\.\w+)*\z/
|
523
|
-
$1.to_sym
|
524
|
-
end
|
525
|
-
if @collection
|
526
|
-
variable_counter = :"#{variable}_counter"
|
527
|
-
variable_iteration = :"#{variable}_iteration"
|
295
|
+
def find_template(path, locals)
|
296
|
+
prefixes = path.include?(?/) ? [] : @lookup_context.prefixes
|
297
|
+
@lookup_context.find_template(path, prefixes, true, locals, @details)
|
528
298
|
end
|
529
|
-
[variable, variable_counter, variable_iteration]
|
530
|
-
end
|
531
|
-
|
532
|
-
IDENTIFIER_ERROR_MESSAGE = "The partial name (%s) is not a valid Ruby identifier; " +
|
533
|
-
"make sure your partial name starts with underscore, " +
|
534
|
-
"and is followed by any combination of letters, numbers and underscores."
|
535
|
-
|
536
|
-
OPTION_AS_ERROR_MESSAGE = "The value (%s) of the option `as` is not a valid Ruby identifier; " +
|
537
|
-
"make sure it starts with lowercase letter, " +
|
538
|
-
"and is followed by any combination of letters, numbers and underscores."
|
539
|
-
|
540
|
-
def raise_invalid_identifier(path)
|
541
|
-
raise ArgumentError.new(IDENTIFIER_ERROR_MESSAGE % (path))
|
542
|
-
end
|
543
|
-
|
544
|
-
def raise_invalid_option_as(as)
|
545
|
-
raise ArgumentError.new(OPTION_AS_ERROR_MESSAGE % (as))
|
546
|
-
end
|
547
299
|
end
|
548
300
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module ActionView
|
2
4
|
# This is the main entry point for rendering. It basically delegates
|
3
5
|
# to other objects like TemplateRenderer and PartialRenderer which
|
@@ -15,16 +17,16 @@ module ActionView
|
|
15
17
|
@lookup_context = lookup_context
|
16
18
|
end
|
17
19
|
|
18
|
-
# Main render entry point shared by
|
20
|
+
# Main render entry point shared by Action View and Action Controller.
|
19
21
|
def render(context, options)
|
20
|
-
|
21
|
-
|
22
|
-
end
|
22
|
+
render_to_object(context, options).body
|
23
|
+
end
|
23
24
|
|
25
|
+
def render_to_object(context, options) # :nodoc:
|
24
26
|
if options.key?(:partial)
|
25
|
-
|
27
|
+
render_partial_to_object(context, options)
|
26
28
|
else
|
27
|
-
|
29
|
+
render_template_to_object(context, options)
|
28
30
|
end
|
29
31
|
end
|
30
32
|
|
@@ -41,14 +43,69 @@ module ActionView
|
|
41
43
|
end
|
42
44
|
end
|
43
45
|
|
44
|
-
# Direct
|
46
|
+
# Direct access to template rendering.
|
45
47
|
def render_template(context, options) #:nodoc:
|
46
|
-
|
48
|
+
render_template_to_object(context, options).body
|
47
49
|
end
|
48
50
|
|
49
51
|
# Direct access to partial rendering.
|
50
52
|
def render_partial(context, options, &block) #:nodoc:
|
51
|
-
|
53
|
+
render_partial_to_object(context, options, &block).body
|
54
|
+
end
|
55
|
+
|
56
|
+
def cache_hits # :nodoc:
|
57
|
+
@cache_hits ||= {}
|
52
58
|
end
|
59
|
+
|
60
|
+
def render_template_to_object(context, options) #:nodoc:
|
61
|
+
TemplateRenderer.new(@lookup_context).render(context, options)
|
62
|
+
end
|
63
|
+
|
64
|
+
def render_partial_to_object(context, options, &block) #:nodoc:
|
65
|
+
partial = options[:partial]
|
66
|
+
if String === partial
|
67
|
+
collection = collection_from_options(options)
|
68
|
+
|
69
|
+
if collection
|
70
|
+
# Collection + Partial
|
71
|
+
renderer = CollectionRenderer.new(@lookup_context, options)
|
72
|
+
renderer.render_collection_with_partial(collection, partial, context, block)
|
73
|
+
else
|
74
|
+
if options.key?(:object)
|
75
|
+
# Object + Partial
|
76
|
+
renderer = ObjectRenderer.new(@lookup_context, options)
|
77
|
+
renderer.render_object_with_partial(options[:object], partial, context, block)
|
78
|
+
else
|
79
|
+
# Partial
|
80
|
+
renderer = PartialRenderer.new(@lookup_context, options)
|
81
|
+
renderer.render(partial, context, block)
|
82
|
+
end
|
83
|
+
end
|
84
|
+
else
|
85
|
+
collection = collection_from_object(partial) || collection_from_options(options)
|
86
|
+
|
87
|
+
if collection
|
88
|
+
# Collection + Derived Partial
|
89
|
+
renderer = CollectionRenderer.new(@lookup_context, options)
|
90
|
+
renderer.render_collection_derive_partial(collection, context, block)
|
91
|
+
else
|
92
|
+
# Object + Derived Partial
|
93
|
+
renderer = ObjectRenderer.new(@lookup_context, options)
|
94
|
+
renderer.render_object_derive_partial(partial, context, block)
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
private
|
100
|
+
def collection_from_options(options)
|
101
|
+
if options.key?(:collection)
|
102
|
+
collection = options[:collection]
|
103
|
+
collection || []
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
def collection_from_object(object)
|
108
|
+
object if object.respond_to?(:to_ary)
|
109
|
+
end
|
53
110
|
end
|
54
111
|
end
|