actionview 7.2.2.2 → 8.0.3
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 +69 -78
- data/README.rdoc +1 -1
- data/lib/action_view/base.rb +6 -9
- data/lib/action_view/dependency_tracker/erb_tracker.rb +36 -27
- data/lib/action_view/dependency_tracker/ruby_tracker.rb +2 -19
- data/lib/action_view/dependency_tracker/wildcard_resolver.rb +32 -0
- data/lib/action_view/dependency_tracker.rb +1 -0
- data/lib/action_view/digestor.rb +6 -2
- data/lib/action_view/gem_version.rb +4 -4
- data/lib/action_view/helpers/asset_tag_helper.rb +2 -2
- data/lib/action_view/helpers/atom_feed_helper.rb +1 -3
- data/lib/action_view/helpers/cache_helper.rb +10 -2
- data/lib/action_view/helpers/date_helper.rb +11 -4
- data/lib/action_view/helpers/form_helper.rb +104 -103
- data/lib/action_view/helpers/form_options_helper.rb +31 -25
- data/lib/action_view/helpers/form_tag_helper.rb +20 -17
- data/lib/action_view/helpers/output_safety_helper.rb +1 -2
- data/lib/action_view/helpers/rendering_helper.rb +160 -50
- data/lib/action_view/helpers/sanitize_helper.rb +6 -0
- data/lib/action_view/helpers/tag_helper.rb +26 -39
- data/lib/action_view/helpers/tags/base.rb +9 -9
- data/lib/action_view/helpers/tags/check_box.rb +2 -2
- data/lib/action_view/helpers/tags/collection_check_boxes.rb +4 -3
- data/lib/action_view/helpers/tags/collection_helpers.rb +2 -1
- data/lib/action_view/helpers/tags/file_field.rb +1 -1
- data/lib/action_view/helpers/tags/label.rb +3 -10
- data/lib/action_view/helpers/tags/radio_button.rb +1 -1
- data/lib/action_view/helpers/tags/select_renderer.rb +1 -1
- data/lib/action_view/helpers/tags/text_area.rb +1 -1
- data/lib/action_view/helpers/tags/text_field.rb +1 -1
- data/lib/action_view/helpers/text_helper.rb +10 -3
- data/lib/action_view/helpers/url_helper.rb +2 -4
- data/lib/action_view/layouts.rb +7 -7
- data/lib/action_view/record_identifier.rb +1 -1
- data/lib/action_view/render_parser/prism_render_parser.rb +13 -1
- data/lib/action_view/render_parser/ripper_render_parser.rb +10 -1
- data/lib/action_view/renderer/partial_renderer.rb +2 -2
- data/lib/action_view/renderer/streaming_template_renderer.rb +8 -2
- data/lib/action_view/renderer/template_renderer.rb +3 -3
- data/lib/action_view/rendering.rb +2 -3
- data/lib/action_view/template/error.rb +11 -0
- data/lib/action_view/template/handlers/erb/erubi.rb +1 -1
- data/lib/action_view/template/handlers/erb.rb +45 -37
- data/lib/action_view/template/raw_file.rb +4 -0
- data/lib/action_view/template/resolver.rb +0 -1
- data/lib/action_view/template.rb +1 -2
- data/lib/action_view/test_case.rb +0 -1
- data/lib/action_view.rb +1 -0
- metadata +12 -11
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require "cgi"
|
|
3
|
+
require "cgi/escape"
|
|
4
|
+
require "cgi/util" if RUBY_VERSION < "3.5"
|
|
4
5
|
require "erb"
|
|
5
6
|
require "active_support/core_ext/string/output_safety"
|
|
6
7
|
require "active_support/core_ext/array/extract_options"
|
|
@@ -496,7 +497,8 @@ module ActionView
|
|
|
496
497
|
# <option value="France">France</option>
|
|
497
498
|
# </optgroup>
|
|
498
499
|
#
|
|
499
|
-
# Parameters
|
|
500
|
+
# ==== Parameters
|
|
501
|
+
#
|
|
500
502
|
# * +grouped_options+ - Accepts a nested array or hash of strings. The first value serves as the
|
|
501
503
|
# <tt><optgroup></tt> label while the second value must be an array of options. The second value can be a
|
|
502
504
|
# nested array of text-value pairs. See <tt>options_for_select</tt> for more info.
|
|
@@ -507,7 +509,8 @@ module ActionView
|
|
|
507
509
|
# which will have the +selected+ attribute set. Note: It is possible for this value to match multiple options
|
|
508
510
|
# as you might have the same option in multiple groups. Each will then get <tt>selected="selected"</tt>.
|
|
509
511
|
#
|
|
510
|
-
# Options
|
|
512
|
+
# ==== Options
|
|
513
|
+
#
|
|
511
514
|
# * <tt>:prompt</tt> - set to true or a prompt string. When the select element doesn't have a value yet, this
|
|
512
515
|
# prepends an option with a generic prompt - "Please select" - or the given prompt string.
|
|
513
516
|
# * <tt>:divider</tt> - the divider for the options groups.
|
|
@@ -599,7 +602,8 @@ module ActionView
|
|
|
599
602
|
|
|
600
603
|
# Returns a string of option tags for the days of the week.
|
|
601
604
|
#
|
|
602
|
-
# Options
|
|
605
|
+
# ====Options
|
|
606
|
+
#
|
|
603
607
|
# * <tt>:index_as_value</tt> - Defaults to false, set to true to use the indexes from
|
|
604
608
|
# <tt>I18n.translate("date.day_names")</tt> as the values. By default, Sunday is always 0.
|
|
605
609
|
# * <tt>:day_format</tt> - The I18n key of the array to use for the weekday options.
|
|
@@ -686,7 +690,7 @@ module ActionView
|
|
|
686
690
|
# if a +User+ model has a +category_id+ field and in the form no category is selected, no +category_id+ parameter is sent. So,
|
|
687
691
|
# any strong parameters idiom like:
|
|
688
692
|
#
|
|
689
|
-
# params.
|
|
693
|
+
# params.expect(user: [...])
|
|
690
694
|
#
|
|
691
695
|
# will raise an error since no <tt>{user: ...}</tt> will be present.
|
|
692
696
|
#
|
|
@@ -723,7 +727,7 @@ module ActionView
|
|
|
723
727
|
# end
|
|
724
728
|
#
|
|
725
729
|
# Sample usage (selecting the associated Author for an instance of Post, <tt>@post</tt>):
|
|
726
|
-
#
|
|
730
|
+
# collection_checkboxes(:post, :author_ids, Author.all, :id, :name_with_initial)
|
|
727
731
|
#
|
|
728
732
|
# If <tt>@post.author_ids</tt> is already <tt>[1]</tt>, this would return:
|
|
729
733
|
# <input id="post_author_ids_1" name="post[author_ids][]" type="checkbox" value="1" checked="checked" />
|
|
@@ -736,8 +740,8 @@ module ActionView
|
|
|
736
740
|
#
|
|
737
741
|
# It is also possible to customize the way the elements will be shown by
|
|
738
742
|
# giving a block to the method:
|
|
739
|
-
#
|
|
740
|
-
# b.label { b.
|
|
743
|
+
# collection_checkboxes(:post, :author_ids, Author.all, :id, :name_with_initial) do |b|
|
|
744
|
+
# b.label { b.checkbox }
|
|
741
745
|
# end
|
|
742
746
|
#
|
|
743
747
|
# The argument passed to the block is a special kind of builder for this
|
|
@@ -746,17 +750,17 @@ module ActionView
|
|
|
746
750
|
# Using it, you can change the label and check box display order or even
|
|
747
751
|
# use the label as wrapper, as in the example above.
|
|
748
752
|
#
|
|
749
|
-
# The builder methods <tt>label</tt> and <tt>
|
|
753
|
+
# The builder methods <tt>label</tt> and <tt>checkbox</tt> also accept
|
|
750
754
|
# extra HTML options:
|
|
751
|
-
#
|
|
752
|
-
# b.label(class: "
|
|
755
|
+
# collection_checkboxes(:post, :author_ids, Author.all, :id, :name_with_initial) do |b|
|
|
756
|
+
# b.label(class: "checkbox") { b.checkbox(class: "checkbox") }
|
|
753
757
|
# end
|
|
754
758
|
#
|
|
755
759
|
# There are also three special methods available: <tt>object</tt>, <tt>text</tt> and
|
|
756
760
|
# <tt>value</tt>, which are the current item being rendered, its text and value methods,
|
|
757
761
|
# respectively. You can use them like this:
|
|
758
|
-
#
|
|
759
|
-
# b.label(:"data-value" => b.value) { b.
|
|
762
|
+
# collection_checkboxes(:post, :author_ids, Author.all, :id, :name_with_initial) do |b|
|
|
763
|
+
# b.label(:"data-value" => b.value) { b.checkbox + b.text }
|
|
760
764
|
# end
|
|
761
765
|
#
|
|
762
766
|
# ==== Gotcha
|
|
@@ -779,9 +783,10 @@ module ActionView
|
|
|
779
783
|
#
|
|
780
784
|
# In the rare case you don't want this hidden field, you can pass the
|
|
781
785
|
# <tt>include_hidden: false</tt> option to the helper method.
|
|
782
|
-
def
|
|
786
|
+
def collection_checkboxes(object, method, collection, value_method, text_method, options = {}, html_options = {}, &block)
|
|
783
787
|
Tags::CollectionCheckBoxes.new(object, method, self, collection, value_method, text_method, options, html_options).render(&block)
|
|
784
788
|
end
|
|
789
|
+
alias_method :collection_check_boxes, :collection_checkboxes
|
|
785
790
|
|
|
786
791
|
private
|
|
787
792
|
def option_html_attributes(element)
|
|
@@ -839,7 +844,7 @@ module ActionView
|
|
|
839
844
|
class FormBuilder
|
|
840
845
|
# Wraps ActionView::Helpers::FormOptionsHelper#select for form builders:
|
|
841
846
|
#
|
|
842
|
-
# <%=
|
|
847
|
+
# <%= form_with model: @post do |f| %>
|
|
843
848
|
# <%= f.select :person_id, Person.all.collect { |p| [ p.name, p.id ] }, include_blank: true %>
|
|
844
849
|
# <%= f.submit %>
|
|
845
850
|
# <% end %>
|
|
@@ -851,7 +856,7 @@ module ActionView
|
|
|
851
856
|
|
|
852
857
|
# Wraps ActionView::Helpers::FormOptionsHelper#collection_select for form builders:
|
|
853
858
|
#
|
|
854
|
-
# <%=
|
|
859
|
+
# <%= form_with model: @post do |f| %>
|
|
855
860
|
# <%= f.collection_select :person_id, Author.all, :id, :name_with_initial, prompt: true %>
|
|
856
861
|
# <%= f.submit %>
|
|
857
862
|
# <% end %>
|
|
@@ -863,7 +868,7 @@ module ActionView
|
|
|
863
868
|
|
|
864
869
|
# Wraps ActionView::Helpers::FormOptionsHelper#grouped_collection_select for form builders:
|
|
865
870
|
#
|
|
866
|
-
# <%=
|
|
871
|
+
# <%= form_with model: @city do |f| %>
|
|
867
872
|
# <%= f.grouped_collection_select :country_id, @continents, :countries, :name, :id, :name %>
|
|
868
873
|
# <%= f.submit %>
|
|
869
874
|
# <% end %>
|
|
@@ -875,7 +880,7 @@ module ActionView
|
|
|
875
880
|
|
|
876
881
|
# Wraps ActionView::Helpers::FormOptionsHelper#time_zone_select for form builders:
|
|
877
882
|
#
|
|
878
|
-
# <%=
|
|
883
|
+
# <%= form_with model: @user do |f| %>
|
|
879
884
|
# <%= f.time_zone_select :time_zone, nil, include_blank: true %>
|
|
880
885
|
# <%= f.submit %>
|
|
881
886
|
# <% end %>
|
|
@@ -887,7 +892,7 @@ module ActionView
|
|
|
887
892
|
|
|
888
893
|
# Wraps ActionView::Helpers::FormOptionsHelper#weekday_select for form builders:
|
|
889
894
|
#
|
|
890
|
-
# <%=
|
|
895
|
+
# <%= form_with model: @user do |f| %>
|
|
891
896
|
# <%= f.weekday_select :weekday, include_blank: true %>
|
|
892
897
|
# <%= f.submit %>
|
|
893
898
|
# <% end %>
|
|
@@ -897,21 +902,22 @@ module ActionView
|
|
|
897
902
|
@template.weekday_select(@object_name, method, objectify_options(options), @default_html_options.merge(html_options))
|
|
898
903
|
end
|
|
899
904
|
|
|
900
|
-
# Wraps ActionView::Helpers::FormOptionsHelper#
|
|
905
|
+
# Wraps ActionView::Helpers::FormOptionsHelper#collection_checkboxes for form builders:
|
|
901
906
|
#
|
|
902
|
-
# <%=
|
|
903
|
-
# <%= f.
|
|
907
|
+
# <%= form_with model: @post do |f| %>
|
|
908
|
+
# <%= f.collection_checkboxes :author_ids, Author.all, :id, :name_with_initial %>
|
|
904
909
|
# <%= f.submit %>
|
|
905
910
|
# <% end %>
|
|
906
911
|
#
|
|
907
912
|
# Please refer to the documentation of the base helper for details.
|
|
908
|
-
def
|
|
909
|
-
@template.
|
|
913
|
+
def collection_checkboxes(method, collection, value_method, text_method, options = {}, html_options = {}, &block)
|
|
914
|
+
@template.collection_checkboxes(@object_name, method, collection, value_method, text_method, objectify_options(options), @default_html_options.merge(html_options), &block)
|
|
910
915
|
end
|
|
916
|
+
alias_method :collection_check_boxes, :collection_checkboxes
|
|
911
917
|
|
|
912
918
|
# Wraps ActionView::Helpers::FormOptionsHelper#collection_radio_buttons for form builders:
|
|
913
919
|
#
|
|
914
|
-
# <%=
|
|
920
|
+
# <%= form_with model: @post do |f| %>
|
|
915
921
|
# <%= f.collection_radio_buttons :author_id, Author.all, :id, :name_with_initial %>
|
|
916
922
|
# <%= f.submit %>
|
|
917
923
|
# <% end %>
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require "cgi"
|
|
3
|
+
require "cgi/escape"
|
|
4
|
+
require "cgi/util" if RUBY_VERSION < "3.5"
|
|
4
5
|
require "action_view/helpers/content_exfiltration_prevention_helper"
|
|
5
6
|
require "action_view/helpers/url_helper"
|
|
6
7
|
require "action_view/helpers/text_helper"
|
|
@@ -393,24 +394,24 @@ module ActionView
|
|
|
393
394
|
# * Any other key creates standard HTML attributes for the tag.
|
|
394
395
|
#
|
|
395
396
|
# ==== Examples
|
|
396
|
-
#
|
|
397
|
+
# textarea_tag 'post'
|
|
397
398
|
# # => <textarea id="post" name="post"></textarea>
|
|
398
399
|
#
|
|
399
|
-
#
|
|
400
|
+
# textarea_tag 'bio', @user.bio
|
|
400
401
|
# # => <textarea id="bio" name="bio">This is my biography.</textarea>
|
|
401
402
|
#
|
|
402
|
-
#
|
|
403
|
+
# textarea_tag 'body', nil, rows: 10, cols: 25
|
|
403
404
|
# # => <textarea cols="25" id="body" name="body" rows="10"></textarea>
|
|
404
405
|
#
|
|
405
|
-
#
|
|
406
|
+
# textarea_tag 'body', nil, size: "25x10"
|
|
406
407
|
# # => <textarea name="body" id="body" cols="25" rows="10"></textarea>
|
|
407
408
|
#
|
|
408
|
-
#
|
|
409
|
+
# textarea_tag 'description', "Description goes here.", disabled: true
|
|
409
410
|
# # => <textarea disabled="disabled" id="description" name="description">Description goes here.</textarea>
|
|
410
411
|
#
|
|
411
|
-
#
|
|
412
|
+
# textarea_tag 'comment', nil, class: 'comment_input'
|
|
412
413
|
# # => <textarea class="comment_input" id="comment" name="comment"></textarea>
|
|
413
|
-
def
|
|
414
|
+
def textarea_tag(name, content = nil, options = {})
|
|
414
415
|
options = options.stringify_keys
|
|
415
416
|
|
|
416
417
|
if size = options.delete("size")
|
|
@@ -422,12 +423,13 @@ module ActionView
|
|
|
422
423
|
|
|
423
424
|
content_tag :textarea, content.to_s.html_safe, { "name" => name, "id" => sanitize_to_id(name) }.update(options)
|
|
424
425
|
end
|
|
426
|
+
alias_method :text_area_tag, :textarea_tag
|
|
425
427
|
|
|
426
428
|
##
|
|
427
429
|
# :call-seq:
|
|
428
|
-
#
|
|
429
|
-
#
|
|
430
|
-
#
|
|
430
|
+
# checkbox_tag(name, options = {})
|
|
431
|
+
# checkbox_tag(name, value, options = {})
|
|
432
|
+
# checkbox_tag(name, value, checked, options = {})
|
|
431
433
|
#
|
|
432
434
|
# Creates a check box form input tag.
|
|
433
435
|
#
|
|
@@ -438,21 +440,21 @@ module ActionView
|
|
|
438
440
|
# * Any other key creates standard HTML options for the tag.
|
|
439
441
|
#
|
|
440
442
|
# ==== Examples
|
|
441
|
-
#
|
|
443
|
+
# checkbox_tag 'accept'
|
|
442
444
|
# # => <input id="accept" name="accept" type="checkbox" value="1" />
|
|
443
445
|
#
|
|
444
|
-
#
|
|
446
|
+
# checkbox_tag 'rock', 'rock music'
|
|
445
447
|
# # => <input id="rock" name="rock" type="checkbox" value="rock music" />
|
|
446
448
|
#
|
|
447
|
-
#
|
|
449
|
+
# checkbox_tag 'receive_email', 'yes', true
|
|
448
450
|
# # => <input checked="checked" id="receive_email" name="receive_email" type="checkbox" value="yes" />
|
|
449
451
|
#
|
|
450
|
-
#
|
|
452
|
+
# checkbox_tag 'tos', 'yes', false, class: 'accept_tos'
|
|
451
453
|
# # => <input class="accept_tos" id="tos" name="tos" type="checkbox" value="yes" />
|
|
452
454
|
#
|
|
453
|
-
#
|
|
455
|
+
# checkbox_tag 'eula', 'accepted', false, disabled: true
|
|
454
456
|
# # => <input disabled="disabled" id="eula" name="eula" type="checkbox" value="accepted" />
|
|
455
|
-
def
|
|
457
|
+
def checkbox_tag(name, *args)
|
|
456
458
|
if args.length >= 4
|
|
457
459
|
raise ArgumentError, "wrong number of arguments (given #{args.length + 1}, expected 1..4)"
|
|
458
460
|
end
|
|
@@ -462,6 +464,7 @@ module ActionView
|
|
|
462
464
|
html_options["checked"] = "checked" if checked
|
|
463
465
|
tag :input, html_options
|
|
464
466
|
end
|
|
467
|
+
alias_method :check_box_tag, :checkbox_tag
|
|
465
468
|
|
|
466
469
|
##
|
|
467
470
|
# :call-seq:
|
|
@@ -38,8 +38,7 @@ module ActionView # :nodoc:
|
|
|
38
38
|
|
|
39
39
|
# Converts the array to a comma-separated sentence where the last element is
|
|
40
40
|
# joined by the connector word. This is the html_safe-aware version of
|
|
41
|
-
# ActiveSupport's
|
|
42
|
-
#
|
|
41
|
+
# ActiveSupport's Array#to_sentence.
|
|
43
42
|
def to_sentence(array, options = {})
|
|
44
43
|
options.assert_valid_keys(:words_connector, :two_words_connector, :last_word_connector, :locale)
|
|
45
44
|
|
|
@@ -1,32 +1,140 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
# :markup: markdown
|
|
4
|
+
|
|
3
5
|
module ActionView
|
|
4
6
|
module Helpers # :nodoc:
|
|
5
|
-
#
|
|
7
|
+
# # Action View Rendering Helpers
|
|
6
8
|
#
|
|
7
|
-
# Implements methods that allow rendering from a view context.
|
|
8
|
-
#
|
|
9
|
-
#
|
|
9
|
+
# Implements methods that allow rendering from a view context. In order to use
|
|
10
|
+
# this module, all you need is to implement view_renderer that returns an
|
|
11
|
+
# ActionView::Renderer object.
|
|
10
12
|
module RenderingHelper
|
|
11
|
-
#
|
|
13
|
+
# Renders a template and returns the result.
|
|
14
|
+
#
|
|
15
|
+
# Pass the template to render as the first argument. This is shorthand
|
|
16
|
+
# syntax for partial rendering, so the template filename should be
|
|
17
|
+
# prefixed with an underscore. The partial renderer looks for the partial
|
|
18
|
+
# template in the directory of the calling template first.
|
|
19
|
+
#
|
|
20
|
+
# <% # app/views/posts/new.html.erb %>
|
|
21
|
+
# <%= render "form" %>
|
|
22
|
+
# # => renders app/views/posts/_form.html.erb
|
|
23
|
+
#
|
|
24
|
+
# Use the complete view path to render a partial from another directory.
|
|
25
|
+
#
|
|
26
|
+
# <% # app/views/posts/show.html.erb %>
|
|
27
|
+
# <%= render "comments/form" %>
|
|
28
|
+
# # => renders app/views/comments/_form.html.erb
|
|
29
|
+
#
|
|
30
|
+
# Without the rendering mode, the second argument can be a Hash of local
|
|
31
|
+
# variable assignments for the template.
|
|
32
|
+
#
|
|
33
|
+
# <% # app/views/posts/new.html.erb %>
|
|
34
|
+
# <%= render "form", post: Post.new %>
|
|
35
|
+
# # => renders app/views/posts/_form.html.erb
|
|
36
|
+
#
|
|
37
|
+
# If the first argument responds to `render_in`, the template will be rendered
|
|
38
|
+
# by calling `render_in` with the current view context.
|
|
39
|
+
#
|
|
40
|
+
# class Greeting
|
|
41
|
+
# def render_in(view_context)
|
|
42
|
+
# view_context.render html: "<h1>Hello, World</h1>"
|
|
43
|
+
# end
|
|
44
|
+
#
|
|
45
|
+
# def format
|
|
46
|
+
# :html
|
|
47
|
+
# end
|
|
48
|
+
# end
|
|
49
|
+
#
|
|
50
|
+
# <%= render Greeting.new %>
|
|
51
|
+
# # => "<h1>Hello, World</h1>"
|
|
52
|
+
#
|
|
53
|
+
# #### Rendering Mode
|
|
54
|
+
#
|
|
55
|
+
# Pass the rendering mode as first argument to override it.
|
|
56
|
+
#
|
|
57
|
+
# `:partial`
|
|
58
|
+
# : See ActionView::PartialRenderer for details.
|
|
59
|
+
#
|
|
60
|
+
# <%= render partial: "form", locals: { post: Post.new } %>
|
|
61
|
+
# # => renders app/views/posts/_form.html.erb
|
|
62
|
+
#
|
|
63
|
+
# `:file`
|
|
64
|
+
# : Renders the contents of a file. This option should **not** be used with
|
|
65
|
+
# unsanitized user input.
|
|
66
|
+
#
|
|
67
|
+
# <%= render file: "/path/to/some/file" %>
|
|
68
|
+
# # => renders /path/to/some/file
|
|
69
|
+
#
|
|
70
|
+
# `:inline`
|
|
71
|
+
# : Renders an ERB template string.
|
|
72
|
+
#
|
|
73
|
+
# <% name = "World" %>
|
|
74
|
+
# <%= render inline: "<h1>Hello, <%= name %>!</h1>" %>
|
|
75
|
+
# # => renders "<h1>Hello, World!</h1>"
|
|
76
|
+
#
|
|
77
|
+
# `:body`
|
|
78
|
+
# : Renders the provided text, and sets the format as `:text`.
|
|
79
|
+
#
|
|
80
|
+
# <%= render body: "Hello, World!" %>
|
|
81
|
+
# # => renders "Hello, World!"
|
|
82
|
+
#
|
|
83
|
+
# `:plain`
|
|
84
|
+
# : Renders the provided text, and sets the format as `:text`.
|
|
85
|
+
#
|
|
86
|
+
# <%= render plain: "Hello, World!" %>
|
|
87
|
+
# # => renders "Hello, World!"
|
|
88
|
+
#
|
|
89
|
+
# `:html`
|
|
90
|
+
# : Renders the provided HTML string, and sets the format as
|
|
91
|
+
# `:html`. If the string is not `html_safe?`, performs HTML escaping on
|
|
92
|
+
# the string before rendering.
|
|
93
|
+
#
|
|
94
|
+
# <%= render html: "<h1>Hello, World!</h1>".html_safe %>
|
|
95
|
+
# # => renders "<h1>Hello, World!</h1>"
|
|
96
|
+
#
|
|
97
|
+
# <%= render html: "<h1>Hello, World!</h1>" %>
|
|
98
|
+
# # => renders "<h1>Hello, World!</h1>"
|
|
99
|
+
#
|
|
100
|
+
# `:renderable`
|
|
101
|
+
# : Renders the provided object by calling `render_in` with the current view
|
|
102
|
+
# context. The format is determined by calling `format` on the
|
|
103
|
+
# renderable if it responds to `format`, falling back to `:html` by
|
|
104
|
+
# default.
|
|
105
|
+
#
|
|
106
|
+
# <%= render renderable: Greeting.new %>
|
|
107
|
+
# # => renders "<h1>Hello, World</h1>"
|
|
108
|
+
#
|
|
109
|
+
#
|
|
110
|
+
# #### Options
|
|
111
|
+
#
|
|
112
|
+
# `:locals`
|
|
113
|
+
# : Hash of local variable assignments for the template.
|
|
114
|
+
#
|
|
115
|
+
# <%= render inline: "<h1>Hello, <%= name %>!</h1>", locals: { name: "World" } %>
|
|
116
|
+
# # => renders "<h1>Hello, World!</h1>"
|
|
117
|
+
#
|
|
118
|
+
# `:formats`
|
|
119
|
+
# : Override the current format to render a template for a different format.
|
|
120
|
+
#
|
|
121
|
+
# <% # app/views/posts/show.html.erb %>
|
|
122
|
+
# <%= render template: "posts/content", formats: [:text] %>
|
|
123
|
+
# # => renders app/views/posts/content.text.erb
|
|
12
124
|
#
|
|
13
|
-
#
|
|
14
|
-
#
|
|
15
|
-
# * <tt>:inline</tt> - Renders an inline template similar to how it's done in the controller.
|
|
16
|
-
# * <tt>:plain</tt> - Renders the text passed in out. Setting the content
|
|
17
|
-
# type as <tt>text/plain</tt>.
|
|
18
|
-
# * <tt>:html</tt> - Renders the HTML safe string passed in out, otherwise
|
|
19
|
-
# performs HTML escape on the string first. Setting the content type as
|
|
20
|
-
# <tt>text/html</tt>.
|
|
21
|
-
# * <tt>:body</tt> - Renders the text passed in, and inherits the content
|
|
22
|
-
# type of <tt>text/plain</tt> from ActionDispatch::Response object.
|
|
125
|
+
# `:variants`
|
|
126
|
+
# : Render a template for a different variant.
|
|
23
127
|
#
|
|
24
|
-
#
|
|
128
|
+
# <% # app/views/posts/show.html.erb %>
|
|
129
|
+
# <%= render template: "posts/content", variants: [:tablet] %>
|
|
130
|
+
# # => renders app/views/posts/content.html+tablet.erb
|
|
25
131
|
#
|
|
26
|
-
#
|
|
27
|
-
#
|
|
132
|
+
# `:handlers`
|
|
133
|
+
# : Render a template for a different handler.
|
|
28
134
|
#
|
|
29
|
-
#
|
|
135
|
+
# <% # app/views/posts/show.html.erb %>
|
|
136
|
+
# <%= render template: "posts/content", handlers: [:builder] %>
|
|
137
|
+
# # => renders app/views/posts/content.html.builder
|
|
30
138
|
def render(options = {}, locals = {}, &block)
|
|
31
139
|
case options
|
|
32
140
|
when Hash
|
|
@@ -47,52 +155,54 @@ module ActionView
|
|
|
47
155
|
end
|
|
48
156
|
|
|
49
157
|
# Overrides _layout_for in the context object so it supports the case a block is
|
|
50
|
-
# passed to a partial. Returns the contents that are yielded to a layout, given
|
|
51
|
-
# name or a block.
|
|
158
|
+
# passed to a partial. Returns the contents that are yielded to a layout, given
|
|
159
|
+
# a name or a block.
|
|
52
160
|
#
|
|
53
|
-
# You can think of a layout as a method that is called with a block. If the user
|
|
54
|
-
#
|
|
55
|
-
# If the user calls simply
|
|
161
|
+
# You can think of a layout as a method that is called with a block. If the user
|
|
162
|
+
# calls `yield :some_name`, the block, by default, returns
|
|
163
|
+
# `content_for(:some_name)`. If the user calls simply `yield`, the default block
|
|
164
|
+
# returns `content_for(:layout)`.
|
|
56
165
|
#
|
|
57
166
|
# The user can override this default by passing a block to the layout:
|
|
58
167
|
#
|
|
59
|
-
#
|
|
60
|
-
#
|
|
61
|
-
#
|
|
62
|
-
#
|
|
168
|
+
# # The template
|
|
169
|
+
# <%= render layout: "my_layout" do %>
|
|
170
|
+
# Content
|
|
171
|
+
# <% end %>
|
|
63
172
|
#
|
|
64
|
-
#
|
|
65
|
-
#
|
|
66
|
-
#
|
|
67
|
-
#
|
|
173
|
+
# # The layout
|
|
174
|
+
# <html>
|
|
175
|
+
# <%= yield %>
|
|
176
|
+
# </html>
|
|
68
177
|
#
|
|
69
|
-
# In this case, instead of the default block, which would return
|
|
70
|
-
# this method returns the block that was passed in to
|
|
178
|
+
# In this case, instead of the default block, which would return `content_for(:layout)`,
|
|
179
|
+
# this method returns the block that was passed in to `render :layout`, and the response
|
|
71
180
|
# would be
|
|
72
181
|
#
|
|
73
|
-
#
|
|
74
|
-
#
|
|
75
|
-
#
|
|
182
|
+
# <html>
|
|
183
|
+
# Content
|
|
184
|
+
# </html>
|
|
76
185
|
#
|
|
77
|
-
# Finally, the block can take block arguments, which can be passed in by
|
|
186
|
+
# Finally, the block can take block arguments, which can be passed in by
|
|
187
|
+
# `yield`:
|
|
78
188
|
#
|
|
79
|
-
#
|
|
80
|
-
#
|
|
81
|
-
#
|
|
82
|
-
#
|
|
189
|
+
# # The template
|
|
190
|
+
# <%= render layout: "my_layout" do |customer| %>
|
|
191
|
+
# Hello <%= customer.name %>
|
|
192
|
+
# <% end %>
|
|
83
193
|
#
|
|
84
|
-
#
|
|
85
|
-
#
|
|
86
|
-
#
|
|
87
|
-
#
|
|
194
|
+
# # The layout
|
|
195
|
+
# <html>
|
|
196
|
+
# <%= yield Struct.new(:name).new("David") %>
|
|
197
|
+
# </html>
|
|
88
198
|
#
|
|
89
|
-
# In this case, the layout would receive the block passed into
|
|
199
|
+
# In this case, the layout would receive the block passed into `render :layout`,
|
|
90
200
|
# and the struct specified would be passed into the block as an argument. The result
|
|
91
201
|
# would be
|
|
92
202
|
#
|
|
93
|
-
#
|
|
94
|
-
#
|
|
95
|
-
#
|
|
203
|
+
# <html>
|
|
204
|
+
# Hello David
|
|
205
|
+
# </html>
|
|
96
206
|
#
|
|
97
207
|
def _layout_for(*args, &block)
|
|
98
208
|
name = args.first
|
|
@@ -24,6 +24,12 @@ module ActionView
|
|
|
24
24
|
#
|
|
25
25
|
# Custom sanitization rules can also be provided.
|
|
26
26
|
#
|
|
27
|
+
# <b>Warning</b>: Adding disallowed tags or attributes to the allowlists may introduce
|
|
28
|
+
# vulnerabilities into your application. Please rely on the default allowlists whenever
|
|
29
|
+
# possible, because they are curated to maintain security and safety. If you think that the
|
|
30
|
+
# default allowlists should be expanded, please {open an issue on the rails-html-sanitizer
|
|
31
|
+
# project}[https://github.com/rails/rails-html-sanitizer/issues].
|
|
32
|
+
#
|
|
27
33
|
# Please note that sanitizing user-provided text does not guarantee that the
|
|
28
34
|
# resulting markup is valid or even well-formed.
|
|
29
35
|
#
|
|
@@ -4,7 +4,6 @@ require "active_support/code_generator"
|
|
|
4
4
|
require "active_support/core_ext/enumerable"
|
|
5
5
|
require "active_support/core_ext/string/output_safety"
|
|
6
6
|
require "active_support/core_ext/string/inflections"
|
|
7
|
-
require "set"
|
|
8
7
|
require "action_view/helpers/capture_helper"
|
|
9
8
|
require "action_view/helpers/output_safety_helper"
|
|
10
9
|
|
|
@@ -48,48 +47,36 @@ module ActionView
|
|
|
48
47
|
include CaptureHelper
|
|
49
48
|
include OutputSafetyHelper
|
|
50
49
|
|
|
51
|
-
def self.define_element(name, code_generator:, method_name: name
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
50
|
+
def self.define_element(name, code_generator:, method_name: name)
|
|
51
|
+
return if method_defined?(name)
|
|
52
|
+
|
|
53
|
+
code_generator.class_eval do |batch|
|
|
54
|
+
batch << "\n" <<
|
|
55
|
+
"def #{method_name}(content = nil, escape: true, **options, &block)" <<
|
|
56
|
+
" tag_string(#{name.inspect}, content, options, escape: escape, &block)" <<
|
|
57
|
+
"end"
|
|
58
58
|
end
|
|
59
59
|
end
|
|
60
60
|
|
|
61
|
-
def self.define_void_element(name, code_generator:, method_name: name
|
|
62
|
-
code_generator.
|
|
63
|
-
batch
|
|
64
|
-
def #{method_name}(
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
Putting content inside a void element (#{name}) is invalid
|
|
68
|
-
according to the HTML5 spec, and so it is being deprecated
|
|
69
|
-
without replacement. In Rails 8.0, passing content as a
|
|
70
|
-
positional argument will raise, and using a block will have
|
|
71
|
-
no effect.
|
|
72
|
-
TEXT
|
|
73
|
-
tag_string("#{name}", content, options, escape: escape, &block)
|
|
74
|
-
else
|
|
75
|
-
self_closing_tag_string("#{name}", options, escape, ">")
|
|
76
|
-
end
|
|
77
|
-
end
|
|
78
|
-
RUBY
|
|
61
|
+
def self.define_void_element(name, code_generator:, method_name: name)
|
|
62
|
+
code_generator.class_eval do |batch|
|
|
63
|
+
batch << "\n" <<
|
|
64
|
+
"def #{method_name}(escape: true, **options, &block)" <<
|
|
65
|
+
" self_closing_tag_string(#{name.inspect}, options, escape, '>')" <<
|
|
66
|
+
"end"
|
|
79
67
|
end
|
|
80
68
|
end
|
|
81
69
|
|
|
82
|
-
def self.define_self_closing_element(name, code_generator:, method_name: name
|
|
83
|
-
code_generator.
|
|
84
|
-
batch
|
|
85
|
-
def #{method_name}(content = nil, escape: true, **options, &block)
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
end
|
|
92
|
-
RUBY
|
|
70
|
+
def self.define_self_closing_element(name, code_generator:, method_name: name)
|
|
71
|
+
code_generator.class_eval do |batch|
|
|
72
|
+
batch << "\n" <<
|
|
73
|
+
"def #{method_name}(content = nil, escape: true, **options, &block)" <<
|
|
74
|
+
" if content || block" <<
|
|
75
|
+
" tag_string(#{name.inspect}, content, options, escape: escape, &block)" <<
|
|
76
|
+
" else" <<
|
|
77
|
+
" self_closing_tag_string(#{name.inspect}, options, escape)" <<
|
|
78
|
+
" end" <<
|
|
79
|
+
"end"
|
|
93
80
|
end
|
|
94
81
|
end
|
|
95
82
|
|
|
@@ -110,8 +97,8 @@ module ActionView
|
|
|
110
97
|
define_void_element :wbr, code_generator: code_generator
|
|
111
98
|
|
|
112
99
|
define_self_closing_element :animate, code_generator: code_generator
|
|
113
|
-
define_self_closing_element :animateMotion, code_generator: code_generator
|
|
114
|
-
define_self_closing_element :animateTransform, code_generator: code_generator
|
|
100
|
+
define_self_closing_element :animateMotion, code_generator: code_generator, method_name: :animate_motion
|
|
101
|
+
define_self_closing_element :animateTransform, code_generator: code_generator, method_name: :animate_transform
|
|
115
102
|
define_self_closing_element :circle, code_generator: code_generator
|
|
116
103
|
define_self_closing_element :ellipse, code_generator: code_generator
|
|
117
104
|
define_self_closing_element :line, code_generator: code_generator
|