actionview 7.0.1 → 7.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +281 -202
- data/MIT-LICENSE +1 -1
- data/README.rdoc +3 -3
- data/app/assets/javascripts/rails-ujs.esm.js +693 -0
- data/app/assets/javascripts/rails-ujs.js +630 -0
- data/lib/action_view/base.rb +33 -12
- data/lib/action_view/buffers.rb +106 -8
- data/lib/action_view/cache_expiry.rb +40 -43
- data/lib/action_view/context.rb +1 -1
- data/lib/action_view/deprecator.rb +7 -0
- data/lib/action_view/digestor.rb +1 -1
- data/lib/action_view/gem_version.rb +2 -2
- data/lib/action_view/helpers/active_model_helper.rb +1 -1
- data/lib/action_view/helpers/asset_tag_helper.rb +133 -48
- data/lib/action_view/helpers/asset_url_helper.rb +13 -12
- data/lib/action_view/helpers/atom_feed_helper.rb +5 -5
- data/lib/action_view/helpers/cache_helper.rb +3 -9
- data/lib/action_view/helpers/capture_helper.rb +26 -12
- data/lib/action_view/helpers/content_exfiltration_prevention_helper.rb +70 -0
- data/lib/action_view/helpers/controller_helper.rb +6 -0
- data/lib/action_view/helpers/csp_helper.rb +2 -2
- data/lib/action_view/helpers/csrf_helper.rb +3 -3
- data/lib/action_view/helpers/date_helper.rb +76 -64
- data/lib/action_view/helpers/debug_helper.rb +3 -3
- data/lib/action_view/helpers/form_helper.rb +62 -31
- data/lib/action_view/helpers/form_options_helper.rb +6 -3
- data/lib/action_view/helpers/form_tag_helper.rb +88 -44
- data/lib/action_view/helpers/javascript_helper.rb +1 -0
- data/lib/action_view/helpers/number_helper.rb +15 -13
- data/lib/action_view/helpers/output_safety_helper.rb +4 -4
- data/lib/action_view/helpers/rendering_helper.rb +5 -6
- data/lib/action_view/helpers/sanitize_helper.rb +34 -15
- data/lib/action_view/helpers/tag_helper.rb +27 -16
- data/lib/action_view/helpers/tags/base.rb +11 -52
- data/lib/action_view/helpers/tags/collection_check_boxes.rb +1 -0
- data/lib/action_view/helpers/tags/collection_radio_buttons.rb +1 -0
- data/lib/action_view/helpers/tags/collection_select.rb +3 -0
- data/lib/action_view/helpers/tags/date_field.rb +1 -1
- data/lib/action_view/helpers/tags/date_select.rb +2 -0
- data/lib/action_view/helpers/tags/datetime_field.rb +14 -6
- data/lib/action_view/helpers/tags/datetime_local_field.rb +11 -2
- data/lib/action_view/helpers/tags/grouped_collection_select.rb +3 -0
- data/lib/action_view/helpers/tags/month_field.rb +1 -1
- data/lib/action_view/helpers/tags/select.rb +4 -1
- data/lib/action_view/helpers/tags/select_renderer.rb +56 -0
- data/lib/action_view/helpers/tags/time_field.rb +1 -1
- data/lib/action_view/helpers/tags/time_zone_select.rb +3 -0
- data/lib/action_view/helpers/tags/week_field.rb +1 -1
- data/lib/action_view/helpers/tags/weekday_select.rb +3 -0
- data/lib/action_view/helpers/tags.rb +2 -0
- data/lib/action_view/helpers/text_helper.rb +33 -17
- data/lib/action_view/helpers/translation_helper.rb +6 -6
- data/lib/action_view/helpers/url_helper.rb +90 -65
- data/lib/action_view/helpers.rb +2 -0
- data/lib/action_view/layouts.rb +13 -8
- data/lib/action_view/log_subscriber.rb +49 -32
- data/lib/action_view/lookup_context.rb +29 -13
- data/lib/action_view/path_registry.rb +57 -0
- data/lib/action_view/path_set.rb +13 -14
- data/lib/action_view/railtie.rb +26 -3
- data/lib/action_view/record_identifier.rb +16 -9
- data/lib/action_view/renderer/abstract_renderer.rb +1 -1
- data/lib/action_view/renderer/collection_renderer.rb +9 -1
- data/lib/action_view/renderer/partial_renderer/collection_caching.rb +21 -3
- data/lib/action_view/renderer/partial_renderer.rb +3 -2
- data/lib/action_view/renderer/renderer.rb +2 -0
- data/lib/action_view/renderer/streaming_template_renderer.rb +3 -2
- data/lib/action_view/renderer/template_renderer.rb +3 -2
- data/lib/action_view/rendering.rb +24 -6
- data/lib/action_view/ripper_ast_parser.rb +6 -6
- data/lib/action_view/routing_url_for.rb +7 -4
- data/lib/action_view/template/error.rb +14 -1
- data/lib/action_view/template/handlers/builder.rb +4 -4
- data/lib/action_view/template/handlers/erb/erubi.rb +23 -27
- data/lib/action_view/template/handlers/erb.rb +73 -1
- data/lib/action_view/template/handlers.rb +1 -1
- data/lib/action_view/template/html.rb +1 -1
- data/lib/action_view/template/raw_file.rb +1 -1
- data/lib/action_view/template/renderable.rb +1 -1
- data/lib/action_view/template/resolver.rb +15 -5
- data/lib/action_view/template/text.rb +1 -1
- data/lib/action_view/template/types.rb +25 -34
- data/lib/action_view/template.rb +227 -53
- data/lib/action_view/template_path.rb +2 -0
- data/lib/action_view/test_case.rb +174 -21
- data/lib/action_view/unbound_template.rb +15 -5
- data/lib/action_view/version.rb +1 -1
- data/lib/action_view/view_paths.rb +19 -28
- data/lib/action_view.rb +4 -1
- data/lib/assets/compiled/rails-ujs.js +36 -5
- metadata +27 -27
|
@@ -7,8 +7,9 @@ require "action_view/helpers/asset_url_helper"
|
|
|
7
7
|
require "action_view/helpers/tag_helper"
|
|
8
8
|
|
|
9
9
|
module ActionView
|
|
10
|
-
# = Action View Asset Tag Helpers
|
|
11
10
|
module Helpers # :nodoc:
|
|
11
|
+
# = Action View Asset Tag \Helpers
|
|
12
|
+
#
|
|
12
13
|
# This module provides methods for generating HTML that links views to assets such
|
|
13
14
|
# as images, JavaScripts, stylesheets, and feeds. These methods do not verify
|
|
14
15
|
# the assets exist before linking to them:
|
|
@@ -41,13 +42,14 @@ module ActionView
|
|
|
41
42
|
# When the Asset Pipeline is enabled, you can pass the name of your manifest as
|
|
42
43
|
# source, and include other JavaScript or CoffeeScript files inside the manifest.
|
|
43
44
|
#
|
|
44
|
-
# If the server supports Early Hints
|
|
45
|
-
#
|
|
45
|
+
# If the server supports HTTP Early Hints, and the +defer+ option is not
|
|
46
|
+
# enabled, \Rails will push a <tt>103 Early Hints</tt> response that links
|
|
47
|
+
# to the assets.
|
|
46
48
|
#
|
|
47
49
|
# ==== Options
|
|
48
50
|
#
|
|
49
51
|
# When the last parameter is a hash you can add HTML attributes using that
|
|
50
|
-
# parameter.
|
|
52
|
+
# parameter. This includes but is not limited to the following options:
|
|
51
53
|
#
|
|
52
54
|
# * <tt>:extname</tt> - Append an extension to the generated URL unless the extension
|
|
53
55
|
# already exists. This only applies for relative URLs.
|
|
@@ -59,6 +61,20 @@ module ActionView
|
|
|
59
61
|
# when it is set to true.
|
|
60
62
|
# * <tt>:nonce</tt> - When set to true, adds an automatic nonce value if
|
|
61
63
|
# you have Content Security Policy enabled.
|
|
64
|
+
# * <tt>:async</tt> - When set to +true+, adds the +async+ HTML
|
|
65
|
+
# attribute, allowing the script to be fetched in parallel to be parsed
|
|
66
|
+
# and evaluated as soon as possible.
|
|
67
|
+
# * <tt>:defer</tt> - When set to +true+, adds the +defer+ HTML
|
|
68
|
+
# attribute, which indicates to the browser that the script is meant to
|
|
69
|
+
# be executed after the document has been parsed. Additionally, prevents
|
|
70
|
+
# sending the Preload Links header.
|
|
71
|
+
#
|
|
72
|
+
# Any other specified options will be treated as HTML attributes for the
|
|
73
|
+
# +script+ tag.
|
|
74
|
+
#
|
|
75
|
+
# For more information regarding how the <tt>:async</tt> and <tt>:defer</tt>
|
|
76
|
+
# options affect the <tt><script></tt> tag, please refer to the
|
|
77
|
+
# {MDN docs}[https://developer.mozilla.org/en-US/docs/Web/HTML/Element/script].
|
|
62
78
|
#
|
|
63
79
|
# ==== Examples
|
|
64
80
|
#
|
|
@@ -86,10 +102,17 @@ module ActionView
|
|
|
86
102
|
#
|
|
87
103
|
# javascript_include_tag "http://www.example.com/xmlhr.js", nonce: true
|
|
88
104
|
# # => <script src="http://www.example.com/xmlhr.js" nonce="..."></script>
|
|
105
|
+
#
|
|
106
|
+
# javascript_include_tag "http://www.example.com/xmlhr.js", async: true
|
|
107
|
+
# # => <script src="http://www.example.com/xmlhr.js" async="async"></script>
|
|
108
|
+
#
|
|
109
|
+
# javascript_include_tag "http://www.example.com/xmlhr.js", defer: true
|
|
110
|
+
# # => <script src="http://www.example.com/xmlhr.js" defer="defer"></script>
|
|
89
111
|
def javascript_include_tag(*sources)
|
|
90
112
|
options = sources.extract_options!.stringify_keys
|
|
91
113
|
path_options = options.extract!("protocol", "extname", "host", "skip_pipeline").symbolize_keys
|
|
92
114
|
preload_links = []
|
|
115
|
+
use_preload_links_header = options["preload_links_header"].nil? ? preload_links_header : options.delete("preload_links_header")
|
|
93
116
|
nopush = options["nopush"].nil? ? true : options.delete("nopush")
|
|
94
117
|
crossorigin = options.delete("crossorigin")
|
|
95
118
|
crossorigin = "anonymous" if crossorigin == true
|
|
@@ -98,7 +121,7 @@ module ActionView
|
|
|
98
121
|
|
|
99
122
|
sources_tags = sources.uniq.map { |source|
|
|
100
123
|
href = path_to_javascript(source, path_options)
|
|
101
|
-
if
|
|
124
|
+
if use_preload_links_header && !options["defer"] && href.present? && !href.start_with?("data:")
|
|
102
125
|
preload_link = "<#{href}>; rel=#{rel}; as=script"
|
|
103
126
|
preload_link += "; crossorigin=#{crossorigin}" unless crossorigin.nil?
|
|
104
127
|
preload_link += "; integrity=#{integrity}" unless integrity.nil?
|
|
@@ -115,7 +138,7 @@ module ActionView
|
|
|
115
138
|
content_tag("script", "", tag_options)
|
|
116
139
|
}.join("\n").html_safe
|
|
117
140
|
|
|
118
|
-
if
|
|
141
|
+
if use_preload_links_header
|
|
119
142
|
send_preload_links_header(preload_links)
|
|
120
143
|
end
|
|
121
144
|
|
|
@@ -130,8 +153,8 @@ module ActionView
|
|
|
130
153
|
# set <tt>extname: false</tt> in the options.
|
|
131
154
|
# You can modify the link attributes by passing a hash as the last argument.
|
|
132
155
|
#
|
|
133
|
-
# If the server supports Early Hints
|
|
134
|
-
#
|
|
156
|
+
# If the server supports HTTP Early Hints, \Rails will push a <tt>103 Early
|
|
157
|
+
# Hints</tt> response that links to the assets.
|
|
135
158
|
#
|
|
136
159
|
# ==== Options
|
|
137
160
|
#
|
|
@@ -170,6 +193,7 @@ module ActionView
|
|
|
170
193
|
def stylesheet_link_tag(*sources)
|
|
171
194
|
options = sources.extract_options!.stringify_keys
|
|
172
195
|
path_options = options.extract!("protocol", "extname", "host", "skip_pipeline").symbolize_keys
|
|
196
|
+
use_preload_links_header = options["preload_links_header"].nil? ? preload_links_header : options.delete("preload_links_header")
|
|
173
197
|
preload_links = []
|
|
174
198
|
crossorigin = options.delete("crossorigin")
|
|
175
199
|
crossorigin = "anonymous" if crossorigin == true
|
|
@@ -178,7 +202,7 @@ module ActionView
|
|
|
178
202
|
|
|
179
203
|
sources_tags = sources.uniq.map { |source|
|
|
180
204
|
href = path_to_stylesheet(source, path_options)
|
|
181
|
-
if
|
|
205
|
+
if use_preload_links_header && href.present? && !href.start_with?("data:")
|
|
182
206
|
preload_link = "<#{href}>; rel=preload; as=style"
|
|
183
207
|
preload_link += "; crossorigin=#{crossorigin}" unless crossorigin.nil?
|
|
184
208
|
preload_link += "; integrity=#{integrity}" unless integrity.nil?
|
|
@@ -198,7 +222,7 @@ module ActionView
|
|
|
198
222
|
tag(:link, tag_options)
|
|
199
223
|
}.join("\n").html_safe
|
|
200
224
|
|
|
201
|
-
if
|
|
225
|
+
if use_preload_links_header
|
|
202
226
|
send_preload_links_header(preload_links)
|
|
203
227
|
end
|
|
204
228
|
|
|
@@ -325,16 +349,17 @@ module ActionView
|
|
|
325
349
|
crossorigin = "anonymous" if crossorigin == true || (crossorigin.blank? && as_type == "font")
|
|
326
350
|
integrity = options[:integrity]
|
|
327
351
|
nopush = options.delete(:nopush) || false
|
|
352
|
+
rel = mime_type == "module" ? "modulepreload" : "preload"
|
|
328
353
|
|
|
329
354
|
link_tag = tag.link(**{
|
|
330
|
-
rel:
|
|
355
|
+
rel: rel,
|
|
331
356
|
href: href,
|
|
332
357
|
as: as_type,
|
|
333
358
|
type: mime_type,
|
|
334
359
|
crossorigin: crossorigin
|
|
335
360
|
}.merge!(options.symbolize_keys))
|
|
336
361
|
|
|
337
|
-
preload_link = "<#{href}>; rel
|
|
362
|
+
preload_link = "<#{href}>; rel=#{rel}; as=#{as_type}"
|
|
338
363
|
preload_link += "; type=#{mime_type}" if mime_type
|
|
339
364
|
preload_link += "; crossorigin=#{crossorigin}" if crossorigin
|
|
340
365
|
preload_link += "; integrity=#{integrity}" if integrity
|
|
@@ -395,7 +420,7 @@ module ActionView
|
|
|
395
420
|
check_for_image_tag_errors(options)
|
|
396
421
|
skip_pipeline = options.delete(:skip_pipeline)
|
|
397
422
|
|
|
398
|
-
options[:src] =
|
|
423
|
+
options[:src] = resolve_asset_source("image", source, skip_pipeline)
|
|
399
424
|
|
|
400
425
|
if options[:srcset] && !options[:srcset].is_a?(String)
|
|
401
426
|
options[:srcset] = options[:srcset].map do |src_path, size|
|
|
@@ -412,11 +437,72 @@ module ActionView
|
|
|
412
437
|
tag("img", options)
|
|
413
438
|
end
|
|
414
439
|
|
|
440
|
+
# Returns an HTML picture tag for the +sources+. If +sources+ is a string,
|
|
441
|
+
# a single picture tag will be returned. If +sources+ is an array, a picture
|
|
442
|
+
# tag with nested source tags for each source will be returned. The
|
|
443
|
+
# +sources+ can be full paths, files that exist in your public images
|
|
444
|
+
# directory, or Active Storage attachments. Since the picture tag requires
|
|
445
|
+
# an img tag, the last element you provide will be used for the img tag.
|
|
446
|
+
# For complete control over the picture tag, a block can be passed, which
|
|
447
|
+
# will populate the contents of the tag accordingly.
|
|
448
|
+
#
|
|
449
|
+
# ==== Options
|
|
450
|
+
#
|
|
451
|
+
# When the last parameter is a hash you can add HTML attributes using that
|
|
452
|
+
# parameter. Apart from all the HTML supported options, the following are supported:
|
|
453
|
+
#
|
|
454
|
+
# * <tt>:image</tt> - Hash of options that are passed directly to the +image_tag+ helper.
|
|
455
|
+
#
|
|
456
|
+
# ==== Examples
|
|
457
|
+
#
|
|
458
|
+
# picture_tag("picture.webp")
|
|
459
|
+
# # => <picture><img src="/images/picture.webp" /></picture>
|
|
460
|
+
# picture_tag("gold.png", :image => { :size => "20" })
|
|
461
|
+
# # => <picture><img height="20" src="/images/gold.png" width="20" /></picture>
|
|
462
|
+
# picture_tag("gold.png", :image => { :size => "45x70" })
|
|
463
|
+
# # => <picture><img height="70" src="/images/gold.png" width="45" /></picture>
|
|
464
|
+
# picture_tag("picture.webp", "picture.png")
|
|
465
|
+
# # => <picture><source srcset="/images/picture.webp" /><source srcset="/images/picture.png" /><img src="/images/picture.png" /></picture>
|
|
466
|
+
# picture_tag("picture.webp", "picture.png", :image => { alt: "Image" })
|
|
467
|
+
# # => <picture><source srcset="/images/picture.webp" /><source srcset="/images/picture.png" /><img alt="Image" src="/images/picture.png" /></picture>
|
|
468
|
+
# picture_tag(["picture.webp", "picture.png"], :image => { alt: "Image" })
|
|
469
|
+
# # => <picture><source srcset="/images/picture.webp" /><source srcset="/images/picture.png" /><img alt="Image" src="/images/picture.png" /></picture>
|
|
470
|
+
# picture_tag(:class => "my-class") { tag(:source, :srcset => image_path("picture.webp")) + image_tag("picture.png", :alt => "Image") }
|
|
471
|
+
# # => <picture class="my-class"><source srcset="/images/picture.webp" /><img alt="Image" src="/images/picture.png" /></picture>
|
|
472
|
+
# picture_tag { tag(:source, :srcset => image_path("picture-small.webp"), :media => "(min-width: 600px)") + tag(:source, :srcset => image_path("picture-big.webp")) + image_tag("picture.png", :alt => "Image") }
|
|
473
|
+
# # => <picture><source srcset="/images/picture-small.webp" media="(min-width: 600px)" /><source srcset="/images/picture-big.webp" /><img alt="Image" src="/images/picture.png" /></picture>
|
|
474
|
+
#
|
|
475
|
+
# Active Storage blobs (images that are uploaded by the users of your app):
|
|
476
|
+
#
|
|
477
|
+
# picture_tag(user.profile_picture)
|
|
478
|
+
# # => <picture><img src="/rails/active_storage/blobs/.../profile_picture.webp" /></picture>
|
|
479
|
+
def picture_tag(*sources, &block)
|
|
480
|
+
sources.flatten!
|
|
481
|
+
options = sources.extract_options!.symbolize_keys
|
|
482
|
+
image_options = options.delete(:image) || {}
|
|
483
|
+
skip_pipeline = options.delete(:skip_pipeline)
|
|
484
|
+
|
|
485
|
+
content_tag("picture", options) do
|
|
486
|
+
if block.present?
|
|
487
|
+
capture(&block).html_safe
|
|
488
|
+
elsif sources.size <= 1
|
|
489
|
+
image_tag(sources.last, image_options)
|
|
490
|
+
else
|
|
491
|
+
source_tags = sources.map do |source|
|
|
492
|
+
tag("source",
|
|
493
|
+
srcset: resolve_asset_source("image", source, skip_pipeline),
|
|
494
|
+
type: Template::Types[File.extname(source)[1..]]&.to_s)
|
|
495
|
+
end
|
|
496
|
+
safe_join(source_tags << image_tag(sources.last, image_options))
|
|
497
|
+
end
|
|
498
|
+
end
|
|
499
|
+
end
|
|
500
|
+
|
|
415
501
|
# Returns an HTML video tag for the +sources+. If +sources+ is a string,
|
|
416
502
|
# a single video tag will be returned. If +sources+ is an array, a video
|
|
417
503
|
# tag with nested source tags for each source will be returned. The
|
|
418
|
-
# +sources+ can be full paths
|
|
419
|
-
# directory.
|
|
504
|
+
# +sources+ can be full paths, files that exist in your public videos
|
|
505
|
+
# directory, or Active Storage attachments.
|
|
420
506
|
#
|
|
421
507
|
# ==== Options
|
|
422
508
|
#
|
|
@@ -455,6 +541,11 @@ module ActionView
|
|
|
455
541
|
# # => <video><source src="/videos/trailer.ogg" /><source src="/videos/trailer.flv" /></video>
|
|
456
542
|
# video_tag(["trailer.ogg", "trailer.flv"], size: "160x120")
|
|
457
543
|
# # => <video height="120" width="160"><source src="/videos/trailer.ogg" /><source src="/videos/trailer.flv" /></video>
|
|
544
|
+
#
|
|
545
|
+
# Active Storage blobs (videos that are uploaded by the users of your app):
|
|
546
|
+
#
|
|
547
|
+
# video_tag(user.intro_video)
|
|
548
|
+
# # => <video src="/rails/active_storage/blobs/.../intro_video.mp4"></video>
|
|
458
549
|
def video_tag(*sources)
|
|
459
550
|
options = sources.extract_options!.symbolize_keys
|
|
460
551
|
public_poster_folder = options.delete(:poster_skip_pipeline)
|
|
@@ -468,8 +559,8 @@ module ActionView
|
|
|
468
559
|
# Returns an HTML audio tag for the +sources+. If +sources+ is a string,
|
|
469
560
|
# a single audio tag will be returned. If +sources+ is an array, an audio
|
|
470
561
|
# tag with nested source tags for each source will be returned. The
|
|
471
|
-
# +sources+ can be full paths
|
|
472
|
-
# directory.
|
|
562
|
+
# +sources+ can be full paths, files that exist in your public audios
|
|
563
|
+
# directory, or Active Storage attachments.
|
|
473
564
|
#
|
|
474
565
|
# When the last parameter is a hash you can add HTML attributes using that
|
|
475
566
|
# parameter.
|
|
@@ -482,6 +573,11 @@ module ActionView
|
|
|
482
573
|
# # => <audio autoplay="autoplay" controls="controls" src="/audios/sound.wav"></audio>
|
|
483
574
|
# audio_tag("sound.wav", "sound.mid")
|
|
484
575
|
# # => <audio><source src="/audios/sound.wav" /><source src="/audios/sound.mid" /></audio>
|
|
576
|
+
#
|
|
577
|
+
# Active Storage blobs (audios that are uploaded by the users of your app):
|
|
578
|
+
#
|
|
579
|
+
# audio_tag(user.name_pronunciation_audio)
|
|
580
|
+
# # => <audio src="/rails/active_storage/blobs/.../name_pronunciation_audio.mp3"></audio>
|
|
485
581
|
def audio_tag(*sources)
|
|
486
582
|
multiple_sources_tag_builder("audio", sources)
|
|
487
583
|
end
|
|
@@ -496,29 +592,29 @@ module ActionView
|
|
|
496
592
|
|
|
497
593
|
if sources.size > 1
|
|
498
594
|
content_tag(type, options) do
|
|
499
|
-
safe_join sources.map { |source| tag("source", src:
|
|
595
|
+
safe_join sources.map { |source| tag("source", src: resolve_asset_source(type, source, skip_pipeline)) }
|
|
500
596
|
end
|
|
501
597
|
else
|
|
502
|
-
options[:src] =
|
|
598
|
+
options[:src] = resolve_asset_source(type, sources.first, skip_pipeline)
|
|
503
599
|
content_tag(type, nil, options)
|
|
504
600
|
end
|
|
505
601
|
end
|
|
506
602
|
|
|
507
|
-
def
|
|
603
|
+
def resolve_asset_source(asset_type, source, skip_pipeline)
|
|
508
604
|
if source.is_a?(Symbol) || source.is_a?(String)
|
|
509
|
-
|
|
605
|
+
path_to_asset(source, type: asset_type.to_sym, skip_pipeline: skip_pipeline)
|
|
510
606
|
else
|
|
511
607
|
polymorphic_url(source)
|
|
512
608
|
end
|
|
513
609
|
rescue NoMethodError => e
|
|
514
|
-
raise ArgumentError, "Can't resolve
|
|
610
|
+
raise ArgumentError, "Can't resolve #{asset_type} into URL: #{e}"
|
|
515
611
|
end
|
|
516
612
|
|
|
517
613
|
def extract_dimensions(size)
|
|
518
614
|
size = size.to_s
|
|
519
|
-
if /\A\d+x\d
|
|
615
|
+
if /\A\d+(?:\.\d+)?x\d+(?:\.\d+)?\z/.match?(size)
|
|
520
616
|
size.split("x")
|
|
521
|
-
elsif /\A\d
|
|
617
|
+
elsif /\A\d+(?:\.\d+)?\z/.match?(size)
|
|
522
618
|
[size, size]
|
|
523
619
|
end
|
|
524
620
|
end
|
|
@@ -539,40 +635,29 @@ module ActionView
|
|
|
539
635
|
end
|
|
540
636
|
end
|
|
541
637
|
|
|
542
|
-
|
|
638
|
+
# Some HTTP client and proxies have a 4kiB header limit, but more importantly
|
|
639
|
+
# including preload links has diminishing returns so it's best to not go overboard
|
|
640
|
+
MAX_HEADER_SIZE = 1_000 # :nodoc:
|
|
641
|
+
|
|
543
642
|
def send_preload_links_header(preload_links, max_header_size: MAX_HEADER_SIZE)
|
|
544
643
|
return if preload_links.empty?
|
|
545
|
-
|
|
644
|
+
response_present = respond_to?(:response) && response
|
|
645
|
+
return if response_present && response.sending?
|
|
546
646
|
|
|
547
647
|
if respond_to?(:request) && request
|
|
548
648
|
request.send_early_hints("Link" => preload_links.join("\n"))
|
|
549
649
|
end
|
|
550
650
|
|
|
551
|
-
if
|
|
552
|
-
header = response.headers["Link"]
|
|
553
|
-
header = header ? header.dup : +""
|
|
554
|
-
|
|
555
|
-
# rindex count characters not bytes, but we assume non-ascii characters
|
|
556
|
-
# are rare in urls, and we have a 192 bytes margin.
|
|
557
|
-
last_line_offset = header.rindex("\n")
|
|
558
|
-
last_line_size = if last_line_offset
|
|
559
|
-
header.bytesize - last_line_offset
|
|
560
|
-
else
|
|
561
|
-
header.bytesize
|
|
562
|
-
end
|
|
563
|
-
|
|
651
|
+
if response_present
|
|
652
|
+
header = +response.headers["Link"].to_s
|
|
564
653
|
preload_links.each do |link|
|
|
565
|
-
if
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
end
|
|
654
|
+
break if header.bytesize + link.bytesize > max_header_size
|
|
655
|
+
|
|
656
|
+
if header.empty?
|
|
657
|
+
header << link
|
|
570
658
|
else
|
|
571
|
-
header << "
|
|
572
|
-
last_line_size = 0
|
|
659
|
+
header << "," << link
|
|
573
660
|
end
|
|
574
|
-
header << link
|
|
575
|
-
last_line_size += link.bytesize
|
|
576
661
|
end
|
|
577
662
|
|
|
578
663
|
response.headers["Link"] = header
|
|
@@ -3,8 +3,9 @@
|
|
|
3
3
|
require "zlib"
|
|
4
4
|
|
|
5
5
|
module ActionView
|
|
6
|
-
# = Action View Asset URL Helpers
|
|
7
6
|
module Helpers # :nodoc:
|
|
7
|
+
# = Action View Asset URL \Helpers
|
|
8
|
+
#
|
|
8
9
|
# This module provides methods for generating asset paths and
|
|
9
10
|
# URLs.
|
|
10
11
|
#
|
|
@@ -16,8 +17,8 @@ module ActionView
|
|
|
16
17
|
#
|
|
17
18
|
# === Using asset hosts
|
|
18
19
|
#
|
|
19
|
-
# By default, Rails links to these assets on the current host in the public
|
|
20
|
-
# folder, but you can direct Rails to link to assets from a dedicated asset
|
|
20
|
+
# By default, \Rails links to these assets on the current host in the public
|
|
21
|
+
# folder, but you can direct \Rails to link to assets from a dedicated asset
|
|
21
22
|
# server by setting <tt>ActionController::Base.asset_host</tt> in the application
|
|
22
23
|
# configuration, typically in <tt>config/environments/production.rb</tt>.
|
|
23
24
|
# For example, you'd define <tt>assets.example.com</tt> to be your asset
|
|
@@ -196,7 +197,7 @@ module ActionView
|
|
|
196
197
|
source = "#{source}#{extname}"
|
|
197
198
|
end
|
|
198
199
|
|
|
199
|
-
|
|
200
|
+
unless source.start_with?(?/)
|
|
200
201
|
if options[:skip_pipeline]
|
|
201
202
|
source = public_compute_asset_path(source, options)
|
|
202
203
|
else
|
|
@@ -219,7 +220,7 @@ module ActionView
|
|
|
219
220
|
|
|
220
221
|
# Computes the full URL to an asset in the public directory. This
|
|
221
222
|
# will use +asset_path+ internally, so most of their behaviors
|
|
222
|
-
# will be the same. If
|
|
223
|
+
# will be the same. If +:host+ options is set, it overwrites global
|
|
223
224
|
# +config.action_controller.asset_host+ setting.
|
|
224
225
|
#
|
|
225
226
|
# All other options provided are forwarded to +asset_path+ call.
|
|
@@ -324,7 +325,7 @@ module ActionView
|
|
|
324
325
|
|
|
325
326
|
# Computes the full URL to a JavaScript asset in the public javascripts directory.
|
|
326
327
|
# This will use +javascript_path+ internally, so most of their behaviors will be the same.
|
|
327
|
-
# Since +javascript_url+ is based on +asset_url+ method you can set
|
|
328
|
+
# Since +javascript_url+ is based on +asset_url+ method you can set +:host+ options. If +:host+
|
|
328
329
|
# options is set, it overwrites global +config.action_controller.asset_host+ setting.
|
|
329
330
|
#
|
|
330
331
|
# javascript_url "js/xmlhr.js", host: "http://stage.example.com" # => http://stage.example.com/assets/js/xmlhr.js
|
|
@@ -351,7 +352,7 @@ module ActionView
|
|
|
351
352
|
|
|
352
353
|
# Computes the full URL to a stylesheet asset in the public stylesheets directory.
|
|
353
354
|
# This will use +stylesheet_path+ internally, so most of their behaviors will be the same.
|
|
354
|
-
# Since +stylesheet_url+ is based on +asset_url+ method you can set
|
|
355
|
+
# Since +stylesheet_url+ is based on +asset_url+ method you can set +:host+ options. If +:host+
|
|
355
356
|
# options is set, it overwrites global +config.action_controller.asset_host+ setting.
|
|
356
357
|
#
|
|
357
358
|
# stylesheet_url "css/style.css", host: "http://stage.example.com" # => http://stage.example.com/assets/css/style.css
|
|
@@ -372,7 +373,7 @@ module ActionView
|
|
|
372
373
|
# image_path("http://www.example.com/img/edit.png") # => "http://www.example.com/img/edit.png"
|
|
373
374
|
#
|
|
374
375
|
# If you have images as application resources this method may conflict with their named routes.
|
|
375
|
-
# The alias +path_to_image+ is provided to avoid that. Rails uses the alias internally, and
|
|
376
|
+
# The alias +path_to_image+ is provided to avoid that. \Rails uses the alias internally, and
|
|
376
377
|
# plugin authors are encouraged to do so.
|
|
377
378
|
def image_path(source, options = {})
|
|
378
379
|
path_to_asset(source, { type: :image }.merge!(options))
|
|
@@ -381,7 +382,7 @@ module ActionView
|
|
|
381
382
|
|
|
382
383
|
# Computes the full URL to an image asset.
|
|
383
384
|
# This will use +image_path+ internally, so most of their behaviors will be the same.
|
|
384
|
-
# Since +image_url+ is based on +asset_url+ method you can set
|
|
385
|
+
# Since +image_url+ is based on +asset_url+ method you can set +:host+ options. If +:host+
|
|
385
386
|
# options is set, it overwrites global +config.action_controller.asset_host+ setting.
|
|
386
387
|
#
|
|
387
388
|
# image_url "edit.png", host: "http://stage.example.com" # => http://stage.example.com/assets/edit.png
|
|
@@ -407,7 +408,7 @@ module ActionView
|
|
|
407
408
|
|
|
408
409
|
# Computes the full URL to a video asset in the public videos directory.
|
|
409
410
|
# This will use +video_path+ internally, so most of their behaviors will be the same.
|
|
410
|
-
# Since +video_url+ is based on +asset_url+ method you can set
|
|
411
|
+
# Since +video_url+ is based on +asset_url+ method you can set +:host+ options. If +:host+
|
|
411
412
|
# options is set, it overwrites global +config.action_controller.asset_host+ setting.
|
|
412
413
|
#
|
|
413
414
|
# video_url "hd.avi", host: "http://stage.example.com" # => http://stage.example.com/videos/hd.avi
|
|
@@ -433,7 +434,7 @@ module ActionView
|
|
|
433
434
|
|
|
434
435
|
# Computes the full URL to an audio asset in the public audios directory.
|
|
435
436
|
# This will use +audio_path+ internally, so most of their behaviors will be the same.
|
|
436
|
-
# Since +audio_url+ is based on +asset_url+ method you can set
|
|
437
|
+
# Since +audio_url+ is based on +asset_url+ method you can set +:host+ options. If +:host+
|
|
437
438
|
# options is set, it overwrites global +config.action_controller.asset_host+ setting.
|
|
438
439
|
#
|
|
439
440
|
# audio_url "horse.wav", host: "http://stage.example.com" # => http://stage.example.com/audios/horse.wav
|
|
@@ -458,7 +459,7 @@ module ActionView
|
|
|
458
459
|
|
|
459
460
|
# Computes the full URL to a font asset.
|
|
460
461
|
# This will use +font_path+ internally, so most of their behaviors will be the same.
|
|
461
|
-
# Since +font_url+ is based on +asset_url+ method you can set
|
|
462
|
+
# Since +font_url+ is based on +asset_url+ method you can set +:host+ options. If +:host+
|
|
462
463
|
# options is set, it overwrites global +config.action_controller.asset_host+ setting.
|
|
463
464
|
#
|
|
464
465
|
# font_url "font.ttf", host: "http://stage.example.com" # => http://stage.example.com/fonts/font.ttf
|
|
@@ -3,8 +3,8 @@
|
|
|
3
3
|
require "set"
|
|
4
4
|
|
|
5
5
|
module ActionView
|
|
6
|
-
# = Action View Atom Feed Helpers
|
|
7
6
|
module Helpers # :nodoc:
|
|
7
|
+
# = Action View Atom Feed \Helpers
|
|
8
8
|
module AtomFeedHelper
|
|
9
9
|
# Adds easy defaults to writing Atom feeds with the Builder template engine (this does not work on ERB or any other
|
|
10
10
|
# template languages).
|
|
@@ -82,9 +82,9 @@ module ActionView
|
|
|
82
82
|
# end
|
|
83
83
|
#
|
|
84
84
|
# The Atom spec defines five elements (content rights title subtitle
|
|
85
|
-
# summary) which may directly contain
|
|
85
|
+
# summary) which may directly contain XHTML content if type: 'xhtml'
|
|
86
86
|
# is specified as an attribute. If so, this helper will take care of
|
|
87
|
-
# the enclosing div and
|
|
87
|
+
# the enclosing div and XHTML namespace declaration. Example usage:
|
|
88
88
|
#
|
|
89
89
|
# entry.summary type: 'xhtml' do |xhtml|
|
|
90
90
|
# xhtml.p pluralize(order.line_items.count, "line item")
|
|
@@ -102,7 +102,7 @@ module ActionView
|
|
|
102
102
|
options[:schema_date] = "2005" # The Atom spec copyright date
|
|
103
103
|
end
|
|
104
104
|
|
|
105
|
-
xml = options.delete(:xml) ||
|
|
105
|
+
xml = options.delete(:xml) || block.binding.local_variable_get(:xml)
|
|
106
106
|
xml.instruct!
|
|
107
107
|
if options[:instruct]
|
|
108
108
|
options[:instruct].each do |target, attrs|
|
|
@@ -134,7 +134,7 @@ module ActionView
|
|
|
134
134
|
end
|
|
135
135
|
|
|
136
136
|
private
|
|
137
|
-
# Delegate to
|
|
137
|
+
# Delegate to XML Builder, first wrapping the element in an XHTML
|
|
138
138
|
# namespaced div element if the method and arguments indicate
|
|
139
139
|
# that an xhtml_block? is desired.
|
|
140
140
|
def method_missing(method, *arguments, &block)
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
module ActionView
|
|
4
|
-
# = Action View Cache Helper
|
|
5
4
|
module Helpers # :nodoc:
|
|
5
|
+
# = Action View Cache \Helpers
|
|
6
6
|
module CacheHelper
|
|
7
7
|
class UncacheableFragmentError < StandardError; end
|
|
8
8
|
|
|
@@ -281,14 +281,8 @@ module ActionView
|
|
|
281
281
|
controller.read_fragment(name, options)
|
|
282
282
|
end
|
|
283
283
|
|
|
284
|
-
def write_fragment_for(name, options)
|
|
285
|
-
|
|
286
|
-
yield
|
|
287
|
-
output_safe = output_buffer.html_safe?
|
|
288
|
-
fragment = output_buffer.slice!(pos..-1)
|
|
289
|
-
if output_safe
|
|
290
|
-
self.output_buffer = output_buffer.class.new(output_buffer)
|
|
291
|
-
end
|
|
284
|
+
def write_fragment_for(name, options, &block)
|
|
285
|
+
fragment = output_buffer.capture(&block)
|
|
292
286
|
controller.write_fragment(name, fragment, options)
|
|
293
287
|
end
|
|
294
288
|
|
|
@@ -3,18 +3,22 @@
|
|
|
3
3
|
require "active_support/core_ext/string/output_safety"
|
|
4
4
|
|
|
5
5
|
module ActionView
|
|
6
|
-
# = Action View Capture Helper
|
|
7
6
|
module Helpers # :nodoc:
|
|
8
|
-
#
|
|
7
|
+
# = Action View Capture \Helpers
|
|
8
|
+
#
|
|
9
|
+
# \CaptureHelper exposes methods to let you extract generated markup which
|
|
9
10
|
# can be used in other parts of a template or layout file.
|
|
10
11
|
#
|
|
11
|
-
# It provides a method to capture blocks into variables through capture and
|
|
12
|
-
# a way to capture a block of markup for use in a layout through
|
|
12
|
+
# It provides a method to capture blocks into variables through #capture and
|
|
13
|
+
# a way to capture a block of markup for use in a layout through #content_for.
|
|
14
|
+
#
|
|
15
|
+
# As well as provides a method when using streaming responses through #provide.
|
|
16
|
+
# See ActionController::Streaming for more information.
|
|
13
17
|
module CaptureHelper
|
|
14
|
-
# The capture method extracts part of a template as a
|
|
18
|
+
# The capture method extracts part of a template as a string object.
|
|
15
19
|
# You can then use this object anywhere in your templates, layout, or helpers.
|
|
16
20
|
#
|
|
17
|
-
# The capture method can be used in ERB templates...
|
|
21
|
+
# The capture method can be used in \ERB templates...
|
|
18
22
|
#
|
|
19
23
|
# <% @greeting = capture do %>
|
|
20
24
|
# Welcome to my shiny new web page! The date and time is
|
|
@@ -40,11 +44,18 @@ module ActionView
|
|
|
40
44
|
#
|
|
41
45
|
# @greeting # => "Welcome to my shiny new web page! The date and time is 2018-09-06 11:09:16 -0500"
|
|
42
46
|
#
|
|
43
|
-
def capture(*args)
|
|
47
|
+
def capture(*args, &block)
|
|
44
48
|
value = nil
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
49
|
+
@output_buffer ||= ActionView::OutputBuffer.new
|
|
50
|
+
buffer = @output_buffer.capture { value = yield(*args) }
|
|
51
|
+
|
|
52
|
+
case string = buffer.presence || value
|
|
53
|
+
when OutputBuffer
|
|
54
|
+
string.to_s
|
|
55
|
+
when ActiveSupport::SafeBuffer
|
|
56
|
+
string
|
|
57
|
+
when String
|
|
58
|
+
ERB::Util.html_escape(string)
|
|
48
59
|
end
|
|
49
60
|
end
|
|
50
61
|
|
|
@@ -121,7 +132,7 @@ module ActionView
|
|
|
121
132
|
# <li><%= link_to 'Home', action: 'index' %></li>
|
|
122
133
|
# <% end %>
|
|
123
134
|
#
|
|
124
|
-
#
|
|
135
|
+
# And in another place:
|
|
125
136
|
#
|
|
126
137
|
# <% content_for :navigation do %>
|
|
127
138
|
# <li><%= link_to 'Login', action: 'login' %></li>
|
|
@@ -137,7 +148,7 @@ module ActionView
|
|
|
137
148
|
# <li><%= link_to 'Home', action: 'index' %></li>
|
|
138
149
|
# <% end %>
|
|
139
150
|
#
|
|
140
|
-
# <%#
|
|
151
|
+
# <%# Add some other content, or use a different template: %>
|
|
141
152
|
#
|
|
142
153
|
# <% content_for :navigation, flush: true do %>
|
|
143
154
|
# <li><%= link_to 'Login', action: 'login' %></li>
|
|
@@ -172,6 +183,8 @@ module ActionView
|
|
|
172
183
|
# concatenate several times to the same buffer when rendering a given
|
|
173
184
|
# template, you should use +content_for+, if not, use +provide+ to tell
|
|
174
185
|
# the layout to stop looking for more contents.
|
|
186
|
+
#
|
|
187
|
+
# See ActionController::Streaming for more information.
|
|
175
188
|
def provide(name, content = nil, &block)
|
|
176
189
|
content = capture(&block) if block_given?
|
|
177
190
|
result = @view_flow.append!(name, content) if content
|
|
@@ -179,6 +192,7 @@ module ActionView
|
|
|
179
192
|
end
|
|
180
193
|
|
|
181
194
|
# <tt>content_for?</tt> checks whether any content has been captured yet using <tt>content_for</tt>.
|
|
195
|
+
#
|
|
182
196
|
# Useful to render parts of your layout differently based on what is in your views.
|
|
183
197
|
#
|
|
184
198
|
# <%# This is the layout %>
|