actionview 7.0.1 → 7.1.1
Sign up to get free protection for your applications and to get access to all the features.
- 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 %>
|