diff options
Diffstat (limited to 'actionview/lib/action_view')
-rw-r--r-- | actionview/lib/action_view/digestor.rb | 2 | ||||
-rw-r--r-- | actionview/lib/action_view/gem_version.rb | 4 | ||||
-rw-r--r-- | actionview/lib/action_view/helpers/asset_tag_helper.rb | 113 | ||||
-rw-r--r-- | actionview/lib/action_view/helpers/asset_url_helper.rb | 24 | ||||
-rw-r--r-- | actionview/lib/action_view/helpers/date_helper.rb | 4 | ||||
-rw-r--r-- | actionview/lib/action_view/helpers/form_helper.rb | 41 | ||||
-rw-r--r-- | actionview/lib/action_view/helpers/form_options_helper.rb | 12 | ||||
-rw-r--r-- | actionview/lib/action_view/helpers/tags/base.rb | 6 | ||||
-rw-r--r-- | actionview/lib/action_view/helpers/tags/label.rb | 4 | ||||
-rw-r--r-- | actionview/lib/action_view/helpers/text_helper.rb | 8 | ||||
-rw-r--r-- | actionview/lib/action_view/helpers/url_helper.rb | 20 | ||||
-rw-r--r-- | actionview/lib/action_view/railtie.rb | 11 | ||||
-rw-r--r-- | actionview/lib/action_view/renderer/streaming_template_renderer.rb | 2 |
13 files changed, 170 insertions, 81 deletions
diff --git a/actionview/lib/action_view/digestor.rb b/actionview/lib/action_view/digestor.rb index dfd62bdcfd..1cf0bd3016 100644 --- a/actionview/lib/action_view/digestor.rb +++ b/actionview/lib/action_view/digestor.rb @@ -89,7 +89,7 @@ module ActionView end def digest(finder, stack = []) - Digest::MD5.hexdigest("#{template.source}-#{dependency_digest(finder, stack)}") + ActiveSupport::Digest.hexdigest("#{template.source}-#{dependency_digest(finder, stack)}") end def dependency_digest(finder, stack) diff --git a/actionview/lib/action_view/gem_version.rb b/actionview/lib/action_view/gem_version.rb index ed92490be7..77ae444a58 100644 --- a/actionview/lib/action_view/gem_version.rb +++ b/actionview/lib/action_view/gem_version.rb @@ -7,8 +7,8 @@ module ActionView end module VERSION - MAJOR = 5 - MINOR = 2 + MAJOR = 6 + MINOR = 0 TINY = 0 PRE = "alpha" diff --git a/actionview/lib/action_view/helpers/asset_tag_helper.rb b/actionview/lib/action_view/helpers/asset_tag_helper.rb index e362f13798..76b1c3fb6e 100644 --- a/actionview/lib/action_view/helpers/asset_tag_helper.rb +++ b/actionview/lib/action_view/helpers/asset_tag_helper.rb @@ -2,6 +2,8 @@ require "active_support/core_ext/array/extract_options" require "active_support/core_ext/hash/keys" +require "active_support/core_ext/object/inclusion" +require "active_support/core_ext/object/try" require "action_view/helpers/asset_url_helper" require "action_view/helpers/tag_helper" @@ -45,11 +47,11 @@ module ActionView # When the last parameter is a hash you can add HTML attributes using that # parameter. The following options are supported: # - # * <tt>:extname</tt> - Append an extension to the generated url unless the extension - # already exists. This only applies for relative urls. - # * <tt>:protocol</tt> - Sets the protocol of the generated url, this option only - # applies when a relative url and +host+ options are provided. - # * <tt>:host</tt> - When a relative url is provided the host is added to the + # * <tt>:extname</tt> - Append an extension to the generated URL unless the extension + # already exists. This only applies for relative URLs. + # * <tt>:protocol</tt> - Sets the protocol of the generated URL. This option only + # applies when a relative URL and +host+ options are provided. + # * <tt>:host</tt> - When a relative URL is provided the host is added to the # that path. # * <tt>:skip_pipeline</tt> - This option is used to bypass the asset pipeline # when it is set to true. @@ -91,7 +93,7 @@ module ActionView content_tag("script".freeze, "", tag_options) }.join("\n").html_safe - request.send_early_hints("Link" => early_hints_links.join("\n")) if respond_to?(:request) + request.send_early_hints("Link" => early_hints_links.join("\n")) if respond_to?(:request) && request sources_tags end @@ -131,7 +133,7 @@ module ActionView sources_tags = sources.uniq.map { |source| href = path_to_stylesheet(source, path_options) - early_hints_links << "<#{href}>; rel=preload; as=stylesheet" + early_hints_links << "<#{href}>; rel=preload; as=style" tag_options = { "rel" => "stylesheet", "media" => "screen", @@ -140,7 +142,7 @@ module ActionView tag(:link, tag_options) }.join("\n").html_safe - request.send_early_hints("Link" => early_hints_links.join("\n")) if respond_to?(:request) + request.send_early_hints("Link" => early_hints_links.join("\n")) if respond_to?(:request) && request sources_tags end @@ -221,8 +223,69 @@ module ActionView }.merge!(options.symbolize_keys)) end + # Returns a link tag that browsers can use to preload the +source+. + # The +source+ can be the path of a resource managed by asset pipeline, + # a full path, or an URI. + # + # ==== Options + # + # * <tt>:type</tt> - Override the auto-generated mime type, defaults to the mime type for +source+ extension. + # * <tt>:as</tt> - Override the auto-generated value for as attribute, calculated using +source+ extension and mime type. + # * <tt>:crossorigin</tt> - Specify the crossorigin attribute, required to load cross-origin resources. + # * <tt>:nopush</tt> - Specify if the use of server push is not desired for the resource. Defaults to +false+. + # + # ==== Examples + # + # preload_link_tag("custom_theme.css") + # # => <link rel="preload" href="/assets/custom_theme.css" as="style" type="text/css" /> + # + # preload_link_tag("/videos/video.webm") + # # => <link rel="preload" href="/videos/video.mp4" as="video" type="video/webm" /> + # + # preload_link_tag(post_path(format: :json), as: "fetch") + # # => <link rel="preload" href="/posts.json" as="fetch" type="application/json" /> + # + # preload_link_tag("worker.js", as: "worker") + # # => <link rel="preload" href="/assets/worker.js" as="worker" type="text/javascript" /> + # + # preload_link_tag("//example.com/font.woff2") + # # => <link rel="preload" href="//example.com/font.woff2" as="font" type="font/woff2" crossorigin="anonymous"/> + # + # preload_link_tag("//example.com/font.woff2", crossorigin: "use-credentials") + # # => <link rel="preload" href="//example.com/font.woff2" as="font" type="font/woff2" crossorigin="use-credentials" /> + # + # preload_link_tag("/media/audio.ogg", nopush: true) + # # => <link rel="preload" href="/media/audio.ogg" as="audio" type="audio/ogg" /> + # + def preload_link_tag(source, options = {}) + href = asset_path(source, skip_pipeline: options.delete(:skip_pipeline)) + extname = File.extname(source).downcase.delete(".") + mime_type = options.delete(:type) || Template::Types[extname].try(:to_s) + as_type = options.delete(:as) || resolve_link_as(extname, mime_type) + crossorigin = options.delete(:crossorigin) + crossorigin = "anonymous" if crossorigin == true || (crossorigin.blank? && as_type == "font") + nopush = options.delete(:nopush) || false + + link_tag = tag.link({ + rel: "preload", + href: href, + as: as_type, + type: mime_type, + crossorigin: crossorigin + }.merge!(options.symbolize_keys)) + + early_hints_link = "<#{href}>; rel=preload; as=#{as_type}" + early_hints_link += "; type=#{mime_type}" if mime_type + early_hints_link += "; crossorigin=#{crossorigin}" if crossorigin + early_hints_link += "; nopush" if nopush + + request.send_early_hints("Link" => early_hints_link) if respond_to?(:request) && request + + link_tag + end + # Returns an HTML image tag for the +source+. The +source+ can be a full - # path, a file or an Active Storage attachment. + # path, a file, or an Active Storage attachment. # # ==== Options # @@ -310,12 +373,13 @@ module ActionView # Returns an HTML video tag for the +sources+. If +sources+ is a string, # a single video tag will be returned. If +sources+ is an array, a video # tag with nested source tags for each source will be returned. The - # +sources+ can be full paths or files that exists in your public videos + # +sources+ can be full paths or files that exist in your public videos # directory. # # ==== Options - # You can add HTML attributes using the +options+. The +options+ supports - # two additional keys for convenience and conformance: + # + # When the last parameter is a hash you can add HTML attributes using that + # parameter. The following options are supported: # # * <tt>:poster</tt> - Set an image (like a screenshot) to be shown # before the video loads. The path is calculated like the +src+ of +image_tag+. @@ -332,7 +396,7 @@ module ActionView # video_tag("trailer.ogg") # # => <video src="/videos/trailer.ogg"></video> # video_tag("trailer.ogg", controls: true, preload: 'none') - # # => <video preload="none" controls="controls" src="/videos/trailer.ogg" ></video> + # # => <video preload="none" controls="controls" src="/videos/trailer.ogg"></video> # video_tag("trailer.m4v", size: "16x10", poster: "screenshot.png") # # => <video src="/videos/trailer.m4v" width="16" height="10" poster="/assets/screenshot.png"></video> # video_tag("trailer.m4v", size: "16x10", poster: "screenshot.png", poster_skip_pipeline: true) @@ -359,9 +423,14 @@ module ActionView end end - # Returns an HTML audio tag for the +source+. - # The +source+ can be full path or file that exists in - # your public audios directory. + # Returns an HTML audio tag for the +sources+. If +sources+ is a string, + # a single audio tag will be returned. If +sources+ is an array, an audio + # tag with nested source tags for each source will be returned. The + # +sources+ can be full paths or files that exist in your public audios + # directory. + # + # When the last parameter is a hash you can add HTML attributes using that + # parameter. # # audio_tag("sound") # # => <audio src="/audios/sound"></audio> @@ -417,6 +486,18 @@ module ActionView raise ArgumentError, "Cannot pass a :size option with a :height or :width option" end end + + def resolve_link_as(extname, mime_type) + if extname == "js" + "script" + elsif extname == "css" + "style" + elsif extname == "vtt" + "track" + elsif (type = mime_type.to_s.split("/")[0]) && type.in?(%w(audio video font)) + type + end + end end end end diff --git a/actionview/lib/action_view/helpers/asset_url_helper.rb b/actionview/lib/action_view/helpers/asset_url_helper.rb index a4dcfc9a6c..8cbe107e41 100644 --- a/actionview/lib/action_view/helpers/asset_url_helper.rb +++ b/actionview/lib/action_view/helpers/asset_url_helper.rb @@ -6,7 +6,7 @@ module ActionView # = Action View Asset URL Helpers module Helpers #:nodoc: # This module provides methods for generating asset paths and - # urls. + # URLs. # # image_path("rails.png") # # => "/assets/rails.png" @@ -57,8 +57,8 @@ module ActionView # You can read more about setting up your DNS CNAME records from your ISP. # # Note: This is purely a browser performance optimization and is not meant - # for server load balancing. See http://www.die.net/musings/page_load_time/ - # for background and http://www.browserscope.org/?category=network for + # for server load balancing. See https://www.die.net/musings/page_load_time/ + # for background and https://www.browserscope.org/?category=network for # connection limit data. # # Alternatively, you can exert more control over the asset host by setting @@ -97,7 +97,7 @@ module ActionView # still sending assets for plain HTTP requests from asset hosts. If you don't # have SSL certificates for each of the asset hosts this technique allows you # to avoid warnings in the client about mixed media. - # Note that the request parameter might not be supplied, e.g. when the assets + # Note that the +request+ parameter might not be supplied, e.g. when the assets # are precompiled via a Rake task. Make sure to use a +Proc+ instead of a lambda, # since a +Proc+ allows missing parameters and sets them to +nil+. # @@ -149,13 +149,13 @@ module ActionView # Below lists scenarios that apply to +asset_path+ whether or not you're # using the asset pipeline. # - # - All fully qualified urls are returned immediately. This bypasses the + # - All fully qualified URLs are returned immediately. This bypasses the # asset pipeline and all other behavior described. # # asset_path("http://www.example.com/js/xmlhr.js") # => "http://www.example.com/js/xmlhr.js" # # - All assets that begin with a forward slash are assumed to be full - # urls and will not be expanded. This will bypass the asset pipeline. + # URLs and will not be expanded. This will bypass the asset pipeline. # # asset_path("/foo.png") # => "/foo.png" # @@ -324,7 +324,7 @@ module ActionView # Since +javascript_url+ is based on +asset_url+ method you can set :host options. If :host # options is set, it overwrites global +config.action_controller.asset_host+ setting. # - # javascript_url "js/xmlhr.js", host: "http://stage.example.com" # => http://stage.example.com/assets/dir/xmlhr.js + # javascript_url "js/xmlhr.js", host: "http://stage.example.com" # => http://stage.example.com/assets/js/xmlhr.js # def javascript_url(source, options = {}) url_to_asset(source, { type: :javascript }.merge!(options)) @@ -351,7 +351,7 @@ module ActionView # Since +stylesheet_url+ is based on +asset_url+ method you can set :host options. If :host # options is set, it overwrites global +config.action_controller.asset_host+ setting. # - # stylesheet_url "css/style.css", host: "http://stage.example.com" # => http://stage.example.com/css/style.css + # stylesheet_url "css/style.css", host: "http://stage.example.com" # => http://stage.example.com/assets/css/style.css # def stylesheet_url(source, options = {}) url_to_asset(source, { type: :stylesheet }.merge!(options)) @@ -381,7 +381,7 @@ module ActionView # Since +image_url+ is based on +asset_url+ method you can set :host options. If :host # options is set, it overwrites global +config.action_controller.asset_host+ setting. # - # image_url "edit.png", host: "http://stage.example.com" # => http://stage.example.com/edit.png + # image_url "edit.png", host: "http://stage.example.com" # => http://stage.example.com/assets/edit.png # def image_url(source, options = {}) url_to_asset(source, { type: :image }.merge!(options)) @@ -407,7 +407,7 @@ module ActionView # Since +video_url+ is based on +asset_url+ method you can set :host options. If :host # options is set, it overwrites global +config.action_controller.asset_host+ setting. # - # video_url "hd.avi", host: "http://stage.example.com" # => http://stage.example.com/hd.avi + # video_url "hd.avi", host: "http://stage.example.com" # => http://stage.example.com/videos/hd.avi # def video_url(source, options = {}) url_to_asset(source, { type: :video }.merge!(options)) @@ -433,7 +433,7 @@ module ActionView # Since +audio_url+ is based on +asset_url+ method you can set :host options. If :host # options is set, it overwrites global +config.action_controller.asset_host+ setting. # - # audio_url "horse.wav", host: "http://stage.example.com" # => http://stage.example.com/horse.wav + # audio_url "horse.wav", host: "http://stage.example.com" # => http://stage.example.com/audios/horse.wav # def audio_url(source, options = {}) url_to_asset(source, { type: :audio }.merge!(options)) @@ -458,7 +458,7 @@ module ActionView # Since +font_url+ is based on +asset_url+ method you can set :host options. If :host # options is set, it overwrites global +config.action_controller.asset_host+ setting. # - # font_url "font.ttf", host: "http://stage.example.com" # => http://stage.example.com/font.ttf + # font_url "font.ttf", host: "http://stage.example.com" # => http://stage.example.com/fonts/font.ttf # def font_url(source, options = {}) url_to_asset(source, { type: :font }.merge!(options)) diff --git a/actionview/lib/action_view/helpers/date_helper.rb b/actionview/lib/action_view/helpers/date_helper.rb index 09040ccbc4..4c45f122fe 100644 --- a/actionview/lib/action_view/helpers/date_helper.rb +++ b/actionview/lib/action_view/helpers/date_helper.rb @@ -116,7 +116,7 @@ module ActionView when 10..19 then locale.t :less_than_x_seconds, count: 20 when 20..39 then locale.t :half_a_minute when 40..59 then locale.t :less_than_x_minutes, count: 1 - else locale.t :x_minutes, count: 1 + else locale.t :x_minutes, count: 1 end when 2...45 then locale.t :x_minutes, count: distance_in_minutes @@ -131,7 +131,7 @@ module ActionView when 43200...86400 then locale.t :about_x_months, count: (distance_in_minutes.to_f / 43200.0).round # 60 days up to 365 days when 86400...525600 then locale.t :x_months, count: (distance_in_minutes.to_f / 43200.0).round - else + else from_year = from_time.year from_year += 1 if from_time.month >= 3 to_year = to_time.year diff --git a/actionview/lib/action_view/helpers/form_helper.rb b/actionview/lib/action_view/helpers/form_helper.rb index 6d2ace8cf8..15aa9ec2dd 100644 --- a/actionview/lib/action_view/helpers/form_helper.rb +++ b/actionview/lib/action_view/helpers/form_helper.rb @@ -19,7 +19,7 @@ module ActionView # compared to using vanilla HTML. # # Typically, a form designed to create or update a resource reflects the - # identity of the resource in several ways: (i) the url that the form is + # identity of the resource in several ways: (i) the URL that the form is # sent to (the form element's +action+ attribute) should result in a request # being routed to the appropriate controller action (with the appropriate <tt>:id</tt> # parameter in the case of an existing resource), (ii) input fields should @@ -166,7 +166,7 @@ module ActionView # So for example you may use a named route directly. When the model is # represented by a string or symbol, as in the example above, if the # <tt>:url</tt> option is not specified, by default the form will be - # sent back to the current url (We will describe below an alternative + # sent back to the current URL (We will describe below an alternative # resource-oriented usage of +form_for+ in which the URL does not need # to be specified explicitly). # * <tt>:namespace</tt> - A namespace for your form to ensure uniqueness of @@ -478,6 +478,8 @@ module ActionView mattr_accessor :form_with_generates_remote_forms, default: true + mattr_accessor :form_with_generates_ids, default: false + # Creates a form tag based on mixing URLs, scopes, or models. # # # Using just a URL: @@ -606,7 +608,7 @@ module ActionView # This is helpful when fragment-caching the form. Remote forms # get the authenticity token from the <tt>meta</tt> tag, so embedding is # unnecessary unless you support browsers without JavaScript. - # * <tt>:local</tt> - By default form submits are remote and unobstrusive XHRs. + # * <tt>:local</tt> - By default form submits are remote and unobtrusive XHRs. # Disable remote submits with <tt>local: true</tt>. # * <tt>:skip_enforcing_utf8</tt> - By default a hidden field named +utf8+ # is output to enforce UTF-8 submits. Set to true to skip the field. @@ -640,16 +642,6 @@ module ActionView # # Where <tt>@document = Document.find(params[:id])</tt>. # - # When using labels +form_with+ requires setting the id on the field being - # labelled: - # - # <%= form_with(model: @post) do |form| %> - # <%= form.label :title %> - # <%= form.text_field :title, id: :post_title %> - # <% end %> - # - # See +label+ for more on how the +for+ attribute is derived. - # # === Mixing with other form helpers # # While +form_with+ uses a FormBuilder object it's possible to mix and @@ -746,7 +738,7 @@ module ActionView # end def form_with(model: nil, scope: nil, url: nil, format: nil, **options) options[:allow_method_names_outside_object] = true - options[:skip_default_ids] = true + options[:skip_default_ids] = !form_with_generates_ids if model url ||= polymorphic_path(model, format: format) @@ -1022,14 +1014,13 @@ module ActionView # <%= fields :comment do |fields| %> # <%= fields.text_field :body %> # <% end %> - # # => <input type="text" name="comment[body]> + # # => <input type="text" name="comment[body]"> # # # Using a model infers the scope and assigns field values: - # <%= fields model: Comment.new(body: "full bodied") do |fields| %< + # <%= fields model: Comment.new(body: "full bodied") do |fields| %> # <%= fields.text_field :body %> # <% end %> - # # => - # <input type="text" name="comment[body] value="full bodied"> + # # => <input type="text" name="comment[body]" value="full bodied"> # # # Using +fields+ with +form_with+: # <%= form_with model: @post do |form| %> @@ -1044,16 +1035,6 @@ module ActionView # or model is yielded, so any generated field names are prefixed with # either the passed scope or the scope inferred from the <tt>:model</tt>. # - # When using labels +fields+ requires setting the id on the field being - # labelled: - # - # <%= fields :comment do |fields| %> - # <%= fields.label :body %> - # <%= fields.text_field :body, id: :comment_body %> - # <% end %> - # - # See +label+ for more on how the +for+ attribute is derived. - # # === Mixing with other form helpers # # While +form_with+ uses a FormBuilder object it's possible to mix and @@ -1072,7 +1053,7 @@ module ActionView # FormOptionsHelper#collection_select and DateHelper#datetime_select. def fields(scope = nil, model: nil, **options, &block) options[:allow_method_names_outside_object] = true - options[:skip_default_ids] = true + options[:skip_default_ids] = !form_with_generates_ids if model scope ||= model_name_from_record_or_class(model).param_key @@ -1985,7 +1966,7 @@ module ActionView # See the docs for the <tt>ActionView::FormHelper.fields</tt> helper method. def fields(scope = nil, model: nil, **options, &block) options[:allow_method_names_outside_object] = true - options[:skip_default_ids] = true + options[:skip_default_ids] = !FormHelper.form_with_generates_ids convert_to_legacy_options(options) diff --git a/actionview/lib/action_view/helpers/form_options_helper.rb b/actionview/lib/action_view/helpers/form_options_helper.rb index 02a44477c1..fe5e0b693e 100644 --- a/actionview/lib/action_view/helpers/form_options_helper.rb +++ b/actionview/lib/action_view/helpers/form_options_helper.rb @@ -214,9 +214,13 @@ module ActionView # * +method+ - The attribute of +object+ corresponding to the select tag # * +collection+ - An array of objects representing the <tt><optgroup></tt> tags. # * +group_method+ - The name of a method which, when called on a member of +collection+, returns an - # array of child objects representing the <tt><option></tt> tags. + # array of child objects representing the <tt><option></tt> tags. It can also be any object that responds + # to +call+, such as a +proc+, that will be called for each member of the +collection+ to retrieve the + # value. # * +group_label_method+ - The name of a method which, when called on a member of +collection+, returns a - # string to be used as the +label+ attribute for its <tt><optgroup></tt> tag. + # string to be used as the +label+ attribute for its <tt><optgroup></tt> tag. It can also be any object + # that responds to +call+, such as a +proc+, that will be called for each member of the +collection+ to + # retrieve the label. # * +option_key_method+ - The name of a method which, when called on a child object of a member of # +collection+, returns a value to be used as the +value+ attribute for its <tt><option></tt> tag. # * +option_value_method+ - The name of a method which, when called on a child object of a member of @@ -457,9 +461,9 @@ module ActionView def option_groups_from_collection_for_select(collection, group_method, group_label_method, option_key_method, option_value_method, selected_key = nil) collection.map do |group| option_tags = options_from_collection_for_select( - group.send(group_method), option_key_method, option_value_method, selected_key) + value_for_collection(group, group_method), option_key_method, option_value_method, selected_key) - content_tag("optgroup".freeze, option_tags, label: group.send(group_label_method)) + content_tag("optgroup".freeze, option_tags, label: value_for_collection(group, group_label_method)) end.join.html_safe end diff --git a/actionview/lib/action_view/helpers/tags/base.rb b/actionview/lib/action_view/helpers/tags/base.rb index 8934a9894c..fed908fcdb 100644 --- a/actionview/lib/action_view/helpers/tags/base.rb +++ b/actionview/lib/action_view/helpers/tags/base.rb @@ -97,7 +97,7 @@ module ActionView index = name_and_id_index(options) options["name"] = options.fetch("name") { tag_name(options["multiple"], index) } - unless skip_default_ids? + if generate_ids? options["id"] = options.fetch("id") { tag_id(index) } if namespace = options.delete("namespace") options["id"] = options["id"] ? "#{namespace}_#{options['id']}" : namespace @@ -183,8 +183,8 @@ module ActionView end end - def skip_default_ids? - @skip_default_ids + def generate_ids? + !@skip_default_ids end end end diff --git a/actionview/lib/action_view/helpers/tags/label.rb b/actionview/lib/action_view/helpers/tags/label.rb index 56b48bbd62..02bd099784 100644 --- a/actionview/lib/action_view/helpers/tags/label.rb +++ b/actionview/lib/action_view/helpers/tags/label.rb @@ -75,10 +75,6 @@ module ActionView def render_component(builder) builder.translation end - - def skip_default_ids? - false # The id is used as the `for` attribute. - end end end end diff --git a/actionview/lib/action_view/helpers/text_helper.rb b/actionview/lib/action_view/helpers/text_helper.rb index 84d38aa416..34138de00e 100644 --- a/actionview/lib/action_view/helpers/text_helper.rb +++ b/actionview/lib/action_view/helpers/text_helper.rb @@ -13,9 +13,9 @@ module ActionView # # ==== Sanitization # - # Most text helpers by default sanitize the given content, but do not escape it. - # This means HTML tags will appear in the page but all malicious code will be removed. - # Let's look at some examples using the +simple_format+ method: + # Most text helpers that generate HTML output sanitize the given input by default, + # but do not escape it. This means HTML tags will appear in the page but all malicious + # code will be removed. Let's look at some examples using the +simple_format+ method: # # simple_format('<a href="http://example.com/">Example</a>') # # => "<p><a href=\"http://example.com/\">Example</a></p>" @@ -128,7 +128,7 @@ module ActionView # # => You searched for: <a href="search?q=rails">rails</a> # # highlight('<a href="javascript:alert(\'no!\')">ruby</a> on rails', 'rails', sanitize: false) - # # => "<a>ruby</a> on <mark>rails</mark>" + # # => <a href="javascript:alert('no!')">ruby</a> on <mark>rails</mark> def highlight(text, phrases, options = {}) text = sanitize(text) if options.fetch(:sanitize, true) diff --git a/actionview/lib/action_view/helpers/url_helper.rb b/actionview/lib/action_view/helpers/url_helper.rb index 9900e0cd03..889562c478 100644 --- a/actionview/lib/action_view/helpers/url_helper.rb +++ b/actionview/lib/action_view/helpers/url_helper.rb @@ -139,6 +139,11 @@ module ActionView # link_to "Profiles", controller: "profiles" # # => <a href="/profiles">Profiles</a> # + # When name is +nil+ the href is presented instead + # + # link_to nil, "http://example.com" + # # => <a href="http://www.example.com">http://www.example.com</a> + # # You can use a block as well if your link target is hard to fit into the name parameter. ERB example: # # <%= link_to(@profile) do %> @@ -589,7 +594,7 @@ module ActionView end def add_method_to_attributes!(html_options, method) - if method && method.to_s.downcase != "get" && html_options["rel"] !~ /nofollow/ + if method_not_get_method?(method) && html_options["rel"] !~ /nofollow/ if html_options["rel"].blank? html_options["rel"] = "nofollow" else @@ -599,6 +604,19 @@ module ActionView html_options["data-method"] = method end + STRINGIFIED_COMMON_METHODS = { + get: "get", + delete: "delete", + patch: "patch", + post: "post", + put: "put", + }.freeze + + def method_not_get_method?(method) + return false unless method + (STRINGIFIED_COMMON_METHODS[method] || method.to_s.downcase) != "get" + end + def token_tag(token = nil, form_options: {}) if token != false && protect_against_forgery? token ||= form_authenticity_token(form_options: form_options) diff --git a/actionview/lib/action_view/railtie.rb b/actionview/lib/action_view/railtie.rb index b22347c55c..73dfb267bb 100644 --- a/actionview/lib/action_view/railtie.rb +++ b/actionview/lib/action_view/railtie.rb @@ -22,8 +22,15 @@ module ActionView initializer "action_view.form_with_generates_remote_forms" do |app| ActiveSupport.on_load(:action_view) do form_with_generates_remote_forms = app.config.action_view.delete(:form_with_generates_remote_forms) - unless form_with_generates_remote_forms.nil? - ActionView::Helpers::FormHelper.form_with_generates_remote_forms = form_with_generates_remote_forms + ActionView::Helpers::FormHelper.form_with_generates_remote_forms = form_with_generates_remote_forms + end + end + + initializer "action_view.form_with_generates_ids" do |app| + ActiveSupport.on_load(:action_view) do + form_with_generates_ids = app.config.action_view.delete(:form_with_generates_ids) + unless form_with_generates_ids.nil? + ActionView::Helpers::FormHelper.form_with_generates_ids = form_with_generates_ids end end end diff --git a/actionview/lib/action_view/renderer/streaming_template_renderer.rb b/actionview/lib/action_view/renderer/streaming_template_renderer.rb index ca49eb1144..276a28ce07 100644 --- a/actionview/lib/action_view/renderer/streaming_template_renderer.rb +++ b/actionview/lib/action_view/renderer/streaming_template_renderer.rb @@ -65,7 +65,9 @@ module ActionView yielder = lambda { |*name| view._layout_for(*name) } instrument(:template, identifier: template.identifier, layout: layout.try(:virtual_path)) do + outer_config = I18n.config fiber = Fiber.new do + I18n.config = outer_config if layout layout.render(view, locals, output, &yielder) else |