actionview 5.2.4.1 → 6.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of actionview might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/CHANGELOG.md +193 -79
- data/MIT-LICENSE +1 -1
- data/README.rdoc +4 -2
- data/lib/action_view.rb +3 -2
- data/lib/action_view/base.rb +107 -10
- data/lib/action_view/buffers.rb +15 -0
- data/lib/action_view/cache_expiry.rb +54 -0
- data/lib/action_view/context.rb +5 -9
- data/lib/action_view/digestor.rb +12 -20
- data/lib/action_view/gem_version.rb +4 -4
- data/lib/action_view/helpers.rb +0 -2
- data/lib/action_view/helpers/asset_tag_helper.rb +7 -30
- data/lib/action_view/helpers/asset_url_helper.rb +4 -3
- data/lib/action_view/helpers/cache_helper.rb +18 -10
- data/lib/action_view/helpers/capture_helper.rb +4 -0
- data/lib/action_view/helpers/csp_helper.rb +4 -2
- data/lib/action_view/helpers/csrf_helper.rb +1 -1
- data/lib/action_view/helpers/date_helper.rb +69 -25
- data/lib/action_view/helpers/form_helper.rb +238 -6
- data/lib/action_view/helpers/form_options_helper.rb +27 -18
- data/lib/action_view/helpers/form_tag_helper.rb +12 -9
- data/lib/action_view/helpers/javascript_helper.rb +9 -8
- data/lib/action_view/helpers/number_helper.rb +5 -0
- data/lib/action_view/helpers/output_safety_helper.rb +1 -1
- data/lib/action_view/helpers/rendering_helper.rb +6 -4
- data/lib/action_view/helpers/sanitize_helper.rb +12 -18
- data/lib/action_view/helpers/tag_helper.rb +7 -6
- data/lib/action_view/helpers/tags/base.rb +9 -5
- data/lib/action_view/helpers/tags/color_field.rb +1 -1
- data/lib/action_view/helpers/tags/translator.rb +1 -6
- data/lib/action_view/helpers/text_helper.rb +3 -3
- data/lib/action_view/helpers/translation_helper.rb +16 -12
- data/lib/action_view/helpers/url_helper.rb +14 -14
- data/lib/action_view/layouts.rb +5 -5
- data/lib/action_view/log_subscriber.rb +6 -6
- data/lib/action_view/lookup_context.rb +73 -31
- data/lib/action_view/path_set.rb +5 -10
- data/lib/action_view/railtie.rb +24 -1
- data/lib/action_view/record_identifier.rb +2 -2
- data/lib/action_view/renderer/abstract_renderer.rb +56 -3
- data/lib/action_view/renderer/partial_renderer.rb +66 -55
- data/lib/action_view/renderer/partial_renderer/collection_caching.rb +62 -16
- data/lib/action_view/renderer/renderer.rb +16 -4
- data/lib/action_view/renderer/streaming_template_renderer.rb +5 -5
- data/lib/action_view/renderer/template_renderer.rb +24 -18
- data/lib/action_view/rendering.rb +51 -31
- data/lib/action_view/routing_url_for.rb +12 -11
- data/lib/action_view/template.rb +102 -70
- data/lib/action_view/template/error.rb +21 -1
- data/lib/action_view/template/handlers.rb +27 -1
- data/lib/action_view/template/handlers/builder.rb +2 -2
- data/lib/action_view/template/handlers/erb.rb +17 -7
- data/lib/action_view/template/handlers/erb/erubi.rb +7 -3
- data/lib/action_view/template/handlers/html.rb +1 -1
- data/lib/action_view/template/handlers/raw.rb +2 -2
- data/lib/action_view/template/html.rb +14 -5
- data/lib/action_view/template/inline.rb +22 -0
- data/lib/action_view/template/raw_file.rb +28 -0
- data/lib/action_view/template/resolver.rb +136 -133
- data/lib/action_view/template/sources.rb +13 -0
- data/lib/action_view/template/sources/file.rb +17 -0
- data/lib/action_view/template/text.rb +5 -3
- data/lib/action_view/test_case.rb +1 -1
- data/lib/action_view/testing/resolvers.rb +33 -20
- data/lib/action_view/unbound_template.rb +32 -0
- data/lib/action_view/view_paths.rb +25 -1
- data/lib/assets/compiled/rails-ujs.js +29 -3
- metadata +25 -17
- data/lib/action_view/helpers/record_tag_helper.rb +0 -23
    
        data/lib/action_view/buffers.rb
    CHANGED
    
    | @@ -3,6 +3,21 @@ | |
| 3 3 | 
             
            require "active_support/core_ext/string/output_safety"
         | 
| 4 4 |  | 
| 5 5 | 
             
            module ActionView
         | 
| 6 | 
            +
              # Used as a buffer for views
         | 
| 7 | 
            +
              #
         | 
| 8 | 
            +
              # The main difference between this and ActiveSupport::SafeBuffer
         | 
| 9 | 
            +
              # is for the methods `<<` and `safe_expr_append=` the inputs are
         | 
| 10 | 
            +
              # checked for nil before they are assigned and `to_s` is called on
         | 
| 11 | 
            +
              # the input. For example:
         | 
| 12 | 
            +
              #
         | 
| 13 | 
            +
              #   obuf = ActionView::OutputBuffer.new "hello"
         | 
| 14 | 
            +
              #   obuf << 5
         | 
| 15 | 
            +
              #   puts obuf # => "hello5"
         | 
| 16 | 
            +
              #
         | 
| 17 | 
            +
              #   sbuf = ActiveSupport::SafeBuffer.new "hello"
         | 
| 18 | 
            +
              #   sbuf << 5
         | 
| 19 | 
            +
              #   puts sbuf # => "hello\u0005"
         | 
| 20 | 
            +
              #
         | 
| 6 21 | 
             
              class OutputBuffer < ActiveSupport::SafeBuffer #:nodoc:
         | 
| 7 22 | 
             
                def initialize(*)
         | 
| 8 23 | 
             
                  super
         | 
| @@ -0,0 +1,54 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            module ActionView
         | 
| 4 | 
            +
              class CacheExpiry
         | 
| 5 | 
            +
                class Executor
         | 
| 6 | 
            +
                  def initialize(watcher:)
         | 
| 7 | 
            +
                    @cache_expiry = CacheExpiry.new(watcher: watcher)
         | 
| 8 | 
            +
                  end
         | 
| 9 | 
            +
             | 
| 10 | 
            +
                  def before(target)
         | 
| 11 | 
            +
                    @cache_expiry.clear_cache_if_necessary
         | 
| 12 | 
            +
                  end
         | 
| 13 | 
            +
                end
         | 
| 14 | 
            +
             | 
| 15 | 
            +
                def initialize(watcher:)
         | 
| 16 | 
            +
                  @watched_dirs = nil
         | 
| 17 | 
            +
                  @watcher_class = watcher
         | 
| 18 | 
            +
                  @watcher = nil
         | 
| 19 | 
            +
                  @mutex = Mutex.new
         | 
| 20 | 
            +
                end
         | 
| 21 | 
            +
             | 
| 22 | 
            +
                def clear_cache_if_necessary
         | 
| 23 | 
            +
                  @mutex.synchronize do
         | 
| 24 | 
            +
                    watched_dirs = dirs_to_watch
         | 
| 25 | 
            +
                    return if watched_dirs.empty?
         | 
| 26 | 
            +
             | 
| 27 | 
            +
                    if watched_dirs != @watched_dirs
         | 
| 28 | 
            +
                      @watched_dirs = watched_dirs
         | 
| 29 | 
            +
                      @watcher = @watcher_class.new([], watched_dirs) do
         | 
| 30 | 
            +
                        clear_cache
         | 
| 31 | 
            +
                      end
         | 
| 32 | 
            +
                      @watcher.execute
         | 
| 33 | 
            +
                    else
         | 
| 34 | 
            +
                      @watcher.execute_if_updated
         | 
| 35 | 
            +
                    end
         | 
| 36 | 
            +
                  end
         | 
| 37 | 
            +
                end
         | 
| 38 | 
            +
             | 
| 39 | 
            +
                def clear_cache
         | 
| 40 | 
            +
                  ActionView::LookupContext::DetailsKey.clear
         | 
| 41 | 
            +
                end
         | 
| 42 | 
            +
             | 
| 43 | 
            +
                private
         | 
| 44 | 
            +
             | 
| 45 | 
            +
                  def dirs_to_watch
         | 
| 46 | 
            +
                    fs_paths = all_view_paths.grep(FileSystemResolver)
         | 
| 47 | 
            +
                    fs_paths.map(&:path).sort.uniq
         | 
| 48 | 
            +
                  end
         | 
| 49 | 
            +
             | 
| 50 | 
            +
                  def all_view_paths
         | 
| 51 | 
            +
                    ActionView::ViewPaths.all_view_paths.flat_map(&:paths)
         | 
| 52 | 
            +
                  end
         | 
| 53 | 
            +
              end
         | 
| 54 | 
            +
            end
         | 
    
        data/lib/action_view/context.rb
    CHANGED
    
    | @@ -1,21 +1,17 @@ | |
| 1 1 | 
             
            # frozen_string_literal: true
         | 
| 2 2 |  | 
| 3 3 | 
             
            module ActionView
         | 
| 4 | 
            -
              module CompiledTemplates #:nodoc:
         | 
| 5 | 
            -
                # holds compiled template code
         | 
| 6 | 
            -
              end
         | 
| 7 | 
            -
             | 
| 8 4 | 
             
              # = Action View Context
         | 
| 9 5 | 
             
              #
         | 
| 10 6 | 
             
              # Action View contexts are supplied to Action Controller to render a template.
         | 
| 11 7 | 
             
              # The default Action View context is ActionView::Base.
         | 
| 12 8 | 
             
              #
         | 
| 13 | 
            -
              # In order to work with  | 
| 14 | 
            -
              # The initialization of the variables used by the context | 
| 15 | 
            -
              # and @virtual_path) is responsibility of the | 
| 16 | 
            -
              # (although you can call _prepare_context | 
| 9 | 
            +
              # In order to work with Action Controller, a Context must just include this
         | 
| 10 | 
            +
              # module. The initialization of the variables used by the context
         | 
| 11 | 
            +
              # (@output_buffer, @view_flow, and @virtual_path) is responsibility of the
         | 
| 12 | 
            +
              # object that includes this module (although you can call _prepare_context
         | 
| 13 | 
            +
              # defined below).
         | 
| 17 14 | 
             
              module Context
         | 
| 18 | 
            -
                include CompiledTemplates
         | 
| 19 15 | 
             
                attr_accessor :output_buffer, :view_flow
         | 
| 20 16 |  | 
| 21 17 | 
             
                # Prepares the context by setting the appropriate instance variables.
         | 
    
        data/lib/action_view/digestor.rb
    CHANGED
    
    | @@ -1,28 +1,24 @@ | |
| 1 1 | 
             
            # frozen_string_literal: true
         | 
| 2 2 |  | 
| 3 | 
            -
            require "concurrent/map"
         | 
| 4 3 | 
             
            require "action_view/dependency_tracker"
         | 
| 5 | 
            -
            require "monitor"
         | 
| 6 4 |  | 
| 7 5 | 
             
            module ActionView
         | 
| 8 6 | 
             
              class Digestor
         | 
| 9 7 | 
             
                @@digest_mutex = Mutex.new
         | 
| 10 8 |  | 
| 11 | 
            -
                module PerExecutionDigestCacheExpiry
         | 
| 12 | 
            -
                  def self.before(target)
         | 
| 13 | 
            -
                    ActionView::LookupContext::DetailsKey.clear
         | 
| 14 | 
            -
                  end
         | 
| 15 | 
            -
                end
         | 
| 16 | 
            -
             | 
| 17 9 | 
             
                class << self
         | 
| 18 10 | 
             
                  # Supported options:
         | 
| 19 11 | 
             
                  #
         | 
| 20 | 
            -
                  # * <tt>name</tt> | 
| 21 | 
            -
                  # * <tt> | 
| 22 | 
            -
                  # * <tt> | 
| 23 | 
            -
                   | 
| 24 | 
            -
             | 
| 25 | 
            -
                     | 
| 12 | 
            +
                  # * <tt>name</tt>         - Template name
         | 
| 13 | 
            +
                  # * <tt>format</tt>       - Template format
         | 
| 14 | 
            +
                  # * <tt>finder</tt>       - An instance of <tt>ActionView::LookupContext</tt>
         | 
| 15 | 
            +
                  # * <tt>dependencies</tt> - An array of dependent views
         | 
| 16 | 
            +
                  def digest(name:, format: nil, finder:, dependencies: nil)
         | 
| 17 | 
            +
                    if dependencies.nil? || dependencies.empty?
         | 
| 18 | 
            +
                      cache_key = "#{name}.#{format}"
         | 
| 19 | 
            +
                    else
         | 
| 20 | 
            +
                      cache_key = [ name, format, dependencies ].flatten.compact.join(".")
         | 
| 21 | 
            +
                    end
         | 
| 26 22 |  | 
| 27 23 | 
             
                    # this is a correctly done double-checked locking idiom
         | 
| 28 24 | 
             
                    # (Concurrent::Map's lookups have volatile semantics)
         | 
| @@ -32,7 +28,7 @@ module ActionView | |
| 32 28 | 
             
                        root = tree(name, finder, partial)
         | 
| 33 29 | 
             
                        dependencies.each do |injected_dep|
         | 
| 34 30 | 
             
                          root.children << Injected.new(injected_dep, nil, nil)
         | 
| 35 | 
            -
                        end
         | 
| 31 | 
            +
                        end if dependencies
         | 
| 36 32 | 
             
                        finder.digest_cache[cache_key] = root.digest(finder)
         | 
| 37 33 | 
             
                      end
         | 
| 38 34 | 
             
                    end
         | 
| @@ -47,8 +43,6 @@ module ActionView | |
| 47 43 | 
             
                    logical_name = name.gsub(%r|/_|, "/")
         | 
| 48 44 |  | 
| 49 45 | 
             
                    if template = find_template(finder, logical_name, [], partial, [])
         | 
| 50 | 
            -
                      finder.rendered_format ||= template.formats.first
         | 
| 51 | 
            -
             | 
| 52 46 | 
             
                      if node = seen[template.identifier] # handle cycles in the tree
         | 
| 53 47 | 
             
                        node
         | 
| 54 48 | 
             
                      else
         | 
| @@ -72,9 +66,7 @@ module ActionView | |
| 72 66 | 
             
                  private
         | 
| 73 67 | 
             
                    def find_template(finder, name, prefixes, partial, keys)
         | 
| 74 68 | 
             
                      finder.disable_cache do
         | 
| 75 | 
            -
                         | 
| 76 | 
            -
                        result = finder.find_all(name, prefixes, partial, keys, formats: [format]).first if format
         | 
| 77 | 
            -
                        result || finder.find_all(name, prefixes, partial, keys).first
         | 
| 69 | 
            +
                        finder.find_all(name, prefixes, partial, keys).first
         | 
| 78 70 | 
             
                      end
         | 
| 79 71 | 
             
                    end
         | 
| 80 72 | 
             
                end
         | 
    
        data/lib/action_view/helpers.rb
    CHANGED
    
    | @@ -23,7 +23,6 @@ module ActionView #:nodoc: | |
| 23 23 | 
             
                autoload :JavaScriptHelper, "action_view/helpers/javascript_helper"
         | 
| 24 24 | 
             
                autoload :NumberHelper
         | 
| 25 25 | 
             
                autoload :OutputSafetyHelper
         | 
| 26 | 
            -
                autoload :RecordTagHelper
         | 
| 27 26 | 
             
                autoload :RenderingHelper
         | 
| 28 27 | 
             
                autoload :SanitizeHelper
         | 
| 29 28 | 
             
                autoload :TagHelper
         | 
| @@ -57,7 +56,6 @@ module ActionView #:nodoc: | |
| 57 56 | 
             
                include JavaScriptHelper
         | 
| 58 57 | 
             
                include NumberHelper
         | 
| 59 58 | 
             
                include OutputSafetyHelper
         | 
| 60 | 
            -
                include RecordTagHelper
         | 
| 61 59 | 
             
                include RenderingHelper
         | 
| 62 60 | 
             
                include SanitizeHelper
         | 
| 63 61 | 
             
                include TagHelper
         | 
| @@ -55,7 +55,7 @@ module ActionView | |
| 55 55 | 
             
                  #   that path.
         | 
| 56 56 | 
             
                  # * <tt>:skip_pipeline</tt>  - This option is used to bypass the asset pipeline
         | 
| 57 57 | 
             
                  #   when it is set to true.
         | 
| 58 | 
            -
                  # * <tt>:nonce | 
| 58 | 
            +
                  # * <tt>:nonce</tt>  - When set to true, adds an automatic nonce value if
         | 
| 59 59 | 
             
                  #   you have Content Security Policy enabled.
         | 
| 60 60 | 
             
                  #
         | 
| 61 61 | 
             
                  # ==== Examples
         | 
| @@ -98,7 +98,7 @@ module ActionView | |
| 98 98 | 
             
                      if tag_options["nonce"] == true
         | 
| 99 99 | 
             
                        tag_options["nonce"] = content_security_policy_nonce
         | 
| 100 100 | 
             
                      end
         | 
| 101 | 
            -
                      content_tag("script" | 
| 101 | 
            +
                      content_tag("script", "", tag_options)
         | 
| 102 102 | 
             
                    }.join("\n").html_safe
         | 
| 103 103 |  | 
| 104 104 | 
             
                    request.send_early_hints("Link" => early_hints_links.join("\n")) if respond_to?(:request) && request
         | 
| @@ -329,14 +329,14 @@ module ActionView | |
| 329 329 | 
             
                  #   image_tag("pic.jpg", srcset: [["pic_1024.jpg", "1024w"], ["pic_1980.jpg", "1980w"]], sizes: "100vw")
         | 
| 330 330 | 
             
                  #   # => <img src="/assets/pic.jpg" srcset="/assets/pic_1024.jpg 1024w, /assets/pic_1980.jpg 1980w" sizes="100vw">
         | 
| 331 331 | 
             
                  #
         | 
| 332 | 
            -
                  # Active Storage (images that are uploaded by the users of your app):
         | 
| 332 | 
            +
                  # Active Storage blobs (images that are uploaded by the users of your app):
         | 
| 333 333 | 
             
                  #
         | 
| 334 334 | 
             
                  #   image_tag(user.avatar)
         | 
| 335 335 | 
             
                  #   # => <img src="/rails/active_storage/blobs/.../tiger.jpg" />
         | 
| 336 | 
            -
                  #   image_tag(user.avatar.variant( | 
| 337 | 
            -
                  #   # => <img src="/rails/active_storage/ | 
| 338 | 
            -
                  #   image_tag(user.avatar.variant( | 
| 339 | 
            -
                  #   # => <img width="100" height="100" src="/rails/active_storage/ | 
| 336 | 
            +
                  #   image_tag(user.avatar.variant(resize_to_limit: [100, 100]))
         | 
| 337 | 
            +
                  #   # => <img src="/rails/active_storage/representations/.../tiger.jpg" />
         | 
| 338 | 
            +
                  #   image_tag(user.avatar.variant(resize_to_limit: [100, 100]), size: '100')
         | 
| 339 | 
            +
                  #   # => <img width="100" height="100" src="/rails/active_storage/representations/.../tiger.jpg" />
         | 
| 340 340 | 
             
                  def image_tag(source, options = {})
         | 
| 341 341 | 
             
                    options = options.symbolize_keys
         | 
| 342 342 | 
             
                    check_for_image_tag_errors(options)
         | 
| @@ -355,29 +355,6 @@ module ActionView | |
| 355 355 | 
             
                    tag("img", options)
         | 
| 356 356 | 
             
                  end
         | 
| 357 357 |  | 
| 358 | 
            -
                  # Returns a string suitable for an HTML image tag alt attribute.
         | 
| 359 | 
            -
                  # The +src+ argument is meant to be an image file path.
         | 
| 360 | 
            -
                  # The method removes the basename of the file path and the digest,
         | 
| 361 | 
            -
                  # if any. It also removes hyphens and underscores from file names and
         | 
| 362 | 
            -
                  # replaces them with spaces, returning a space-separated, titleized
         | 
| 363 | 
            -
                  # string.
         | 
| 364 | 
            -
                  #
         | 
| 365 | 
            -
                  # ==== Examples
         | 
| 366 | 
            -
                  #
         | 
| 367 | 
            -
                  #   image_alt('rails.png')
         | 
| 368 | 
            -
                  #   # => Rails
         | 
| 369 | 
            -
                  #
         | 
| 370 | 
            -
                  #   image_alt('hyphenated-file-name.png')
         | 
| 371 | 
            -
                  #   # => Hyphenated file name
         | 
| 372 | 
            -
                  #
         | 
| 373 | 
            -
                  #   image_alt('underscored_file_name.png')
         | 
| 374 | 
            -
                  #   # => Underscored file name
         | 
| 375 | 
            -
                  def image_alt(src)
         | 
| 376 | 
            -
                    ActiveSupport::Deprecation.warn("image_alt is deprecated and will be removed from Rails 6.0. You must explicitly set alt text on images.")
         | 
| 377 | 
            -
             | 
| 378 | 
            -
                    File.basename(src, ".*".freeze).sub(/-[[:xdigit:]]{32,64}\z/, "".freeze).tr("-_".freeze, " ".freeze).capitalize
         | 
| 379 | 
            -
                  end
         | 
| 380 | 
            -
             | 
| 381 358 | 
             
                  # Returns an HTML video tag for the +sources+. If +sources+ is a string,
         | 
| 382 359 | 
             
                  # a single video tag will be returned. If +sources+ is an array, a video
         | 
| 383 360 | 
             
                  # tag with nested source tags for each source will be returned. The
         | 
| @@ -98,8 +98,9 @@ module ActionView | |
| 98 98 | 
             
                # have SSL certificates for each of the asset hosts this technique allows you
         | 
| 99 99 | 
             
                # to avoid warnings in the client about mixed media.
         | 
| 100 100 | 
             
                # Note that the +request+ parameter might not be supplied, e.g. when the assets
         | 
| 101 | 
            -
                # are precompiled  | 
| 102 | 
            -
                # since a +Proc+ allows missing parameters and sets them | 
| 101 | 
            +
                # are precompiled with the command `rails assets:precompile`. Make sure to use a
         | 
| 102 | 
            +
                # +Proc+ instead of a lambda, since a +Proc+ allows missing parameters and sets them
         | 
| 103 | 
            +
                # to +nil+.
         | 
| 103 104 | 
             
                #
         | 
| 104 105 | 
             
                #   config.action_controller.asset_host = Proc.new { |source, request|
         | 
| 105 106 | 
             
                #     if request && request.ssl?
         | 
| @@ -187,7 +188,7 @@ module ActionView | |
| 187 188 | 
             
                    return "" if source.blank?
         | 
| 188 189 | 
             
                    return source if URI_REGEXP.match?(source)
         | 
| 189 190 |  | 
| 190 | 
            -
                    tail, source = source[/([\?#].+)$/], source.sub(/([\?#].+)$/, "" | 
| 191 | 
            +
                    tail, source = source[/([\?#].+)$/], source.sub(/([\?#].+)$/, "")
         | 
| 191 192 |  | 
| 192 193 | 
             
                    if extname = compute_asset_extname(source, options)
         | 
| 193 194 | 
             
                      source = "#{source}#{extname}"
         | 
| @@ -201,34 +201,42 @@ module ActionView | |
| 201 201 | 
             
                  end
         | 
| 202 202 |  | 
| 203 203 | 
             
                  # This helper returns the name of a cache key for a given fragment cache
         | 
| 204 | 
            -
                  # call. By supplying  | 
| 204 | 
            +
                  # call. By supplying <tt>skip_digest: true</tt> to cache, the digestion of cache
         | 
| 205 205 | 
             
                  # fragments can be manually bypassed. This is useful when cache fragments
         | 
| 206 206 | 
             
                  # cannot be manually expired unless you know the exact key which is the
         | 
| 207 207 | 
             
                  # case when using memcached.
         | 
| 208 208 | 
             
                  #
         | 
| 209 209 | 
             
                  # The digest will be generated using +virtual_path:+ if it is provided.
         | 
| 210 210 | 
             
                  #
         | 
| 211 | 
            -
                  def cache_fragment_name(name = {}, skip_digest: nil, virtual_path: nil)
         | 
| 211 | 
            +
                  def cache_fragment_name(name = {}, skip_digest: nil, virtual_path: nil, digest_path: nil)
         | 
| 212 212 | 
             
                    if skip_digest
         | 
| 213 213 | 
             
                      name
         | 
| 214 214 | 
             
                    else
         | 
| 215 | 
            -
                      fragment_name_with_digest(name, virtual_path)
         | 
| 215 | 
            +
                      fragment_name_with_digest(name, virtual_path, digest_path)
         | 
| 216 | 
            +
                    end
         | 
| 217 | 
            +
                  end
         | 
| 218 | 
            +
             | 
| 219 | 
            +
                  def digest_path_from_template(template) # :nodoc:
         | 
| 220 | 
            +
                    digest = Digestor.digest(name: template.virtual_path, format: template.format, finder: lookup_context, dependencies: view_cache_dependencies)
         | 
| 221 | 
            +
             | 
| 222 | 
            +
                    if digest.present?
         | 
| 223 | 
            +
                      "#{template.virtual_path}:#{digest}"
         | 
| 224 | 
            +
                    else
         | 
| 225 | 
            +
                      template.virtual_path
         | 
| 216 226 | 
             
                    end
         | 
| 217 227 | 
             
                  end
         | 
| 218 228 |  | 
| 219 229 | 
             
                private
         | 
| 220 230 |  | 
| 221 | 
            -
                  def fragment_name_with_digest(name, virtual_path)
         | 
| 231 | 
            +
                  def fragment_name_with_digest(name, virtual_path, digest_path)
         | 
| 222 232 | 
             
                    virtual_path ||= @virtual_path
         | 
| 223 233 |  | 
| 224 | 
            -
                    if virtual_path
         | 
| 234 | 
            +
                    if virtual_path || digest_path
         | 
| 225 235 | 
             
                      name = controller.url_for(name).split("://").last if name.is_a?(Hash)
         | 
| 226 236 |  | 
| 227 | 
            -
                       | 
| 228 | 
            -
             | 
| 229 | 
            -
                       | 
| 230 | 
            -
                        [ virtual_path, name ]
         | 
| 231 | 
            -
                      end
         | 
| 237 | 
            +
                      digest_path ||= digest_path_from_template(@current_template)
         | 
| 238 | 
            +
             | 
| 239 | 
            +
                      [ digest_path, name ]
         | 
| 232 240 | 
             
                    else
         | 
| 233 241 | 
             
                      name
         | 
| 234 242 | 
             
                    end
         | 
| @@ -36,6 +36,10 @@ module ActionView | |
| 36 36 | 
             
                  #   </body>
         | 
| 37 37 | 
             
                  #   </html>
         | 
| 38 38 | 
             
                  #
         | 
| 39 | 
            +
                  # The return of capture is the string generated by the block. For Example:
         | 
| 40 | 
            +
                  #
         | 
| 41 | 
            +
                  #   @greeting # => "Welcome to my shiny new web page! The date and time is 2018-09-06 11:09:16 -0500"
         | 
| 42 | 
            +
                  #
         | 
| 39 43 | 
             
                  def capture(*args)
         | 
| 40 44 | 
             
                    value = nil
         | 
| 41 45 | 
             
                    buffer = with_output_buffer { value = yield(*args) }
         | 
| @@ -14,9 +14,11 @@ module ActionView | |
| 14 14 | 
             
                  # This is used by the Rails UJS helper to create dynamically
         | 
| 15 15 | 
             
                  # loaded inline <script> elements.
         | 
| 16 16 | 
             
                  #
         | 
| 17 | 
            -
                  def csp_meta_tag
         | 
| 17 | 
            +
                  def csp_meta_tag(**options)
         | 
| 18 18 | 
             
                    if content_security_policy?
         | 
| 19 | 
            -
                       | 
| 19 | 
            +
                      options[:name] = "csp-nonce"
         | 
| 20 | 
            +
                      options[:content] = content_security_policy_nonce
         | 
| 21 | 
            +
                      tag("meta", options)
         | 
| 20 22 | 
             
                    end
         | 
| 21 23 | 
             
                  end
         | 
| 22 24 | 
             
                end
         | 
| @@ -20,7 +20,7 @@ module ActionView | |
| 20 20 | 
             
                  # "X-CSRF-Token" HTTP header. If you are using rails-ujs this happens automatically.
         | 
| 21 21 | 
             
                  #
         | 
| 22 22 | 
             
                  def csrf_meta_tags
         | 
| 23 | 
            -
                    if protect_against_forgery?
         | 
| 23 | 
            +
                    if defined?(protect_against_forgery?) && protect_against_forgery?
         | 
| 24 24 | 
             
                      [
         | 
| 25 25 | 
             
                        tag("meta", name: "csrf-param", content: request_forgery_protection_token),
         | 
| 26 26 | 
             
                        tag("meta", name: "csrf-token", content: form_authenticity_token)
         | 
| @@ -205,6 +205,7 @@ module ActionView | |
| 205 205 | 
             
                  # * <tt>:end_year</tt>          - Set the end year for the year select. Default is <tt>Date.today.year + 5</tt> if
         | 
| 206 206 | 
             
                  #   you are creating new record. While editing existing record, <tt>:end_year</tt> defaults to
         | 
| 207 207 | 
             
                  #   the current selected year plus 5.
         | 
| 208 | 
            +
                  # * <tt>:year_format</tt>       - Set format of years for year select. Lambda should be passed.
         | 
| 208 209 | 
             
                  # * <tt>:discard_day</tt>       - Set to true if you don't want to show a day select. This includes the day
         | 
| 209 210 | 
             
                  #   as a hidden field instead of showing a select field. Also note that this implicitly sets the day to be the
         | 
| 210 211 | 
             
                  #   first of the given month in order to not create invalid dates like 31 February.
         | 
| @@ -275,6 +276,9 @@ module ActionView | |
| 275 276 | 
             
                  #   # Generates a date select with custom prompts.
         | 
| 276 277 | 
             
                  #   date_select("article", "written_on", prompt: { day: 'Select day', month: 'Select month', year: 'Select year' })
         | 
| 277 278 | 
             
                  #
         | 
| 279 | 
            +
                  #   # Generates a date select with custom year format.
         | 
| 280 | 
            +
                  #   date_select("article", "written_on", year_format: ->(year) { "Heisei #{year - 1988}" })
         | 
| 281 | 
            +
                  #
         | 
| 278 282 | 
             
                  # The selects are prepared for multi-parameter assignment to an Active Record object.
         | 
| 279 283 | 
             
                  #
         | 
| 280 284 | 
             
                  # Note: If the day is not included as an option but the month is, the day will be set to the 1st to ensure that
         | 
| @@ -302,15 +306,15 @@ module ActionView | |
| 302 306 | 
             
                  #   time_select("article", "start_time", include_seconds: true)
         | 
| 303 307 | 
             
                  #
         | 
| 304 308 | 
             
                  #   # You can set the <tt>:minute_step</tt> to 15 which will give you: 00, 15, 30, and 45.
         | 
| 305 | 
            -
                  #   time_select 'game', 'game_time', {minute_step: 15}
         | 
| 309 | 
            +
                  #   time_select 'game', 'game_time', { minute_step: 15 }
         | 
| 306 310 | 
             
                  #
         | 
| 307 311 | 
             
                  #   # Creates a time select tag with a custom prompt. Use <tt>prompt: true</tt> for generic prompts.
         | 
| 308 | 
            -
                  #   time_select("article", "written_on", prompt: {hour: 'Choose hour', minute: 'Choose minute', second: 'Choose seconds'})
         | 
| 309 | 
            -
                  #   time_select("article", "written_on", prompt: {hour: true}) # generic prompt for hours
         | 
| 312 | 
            +
                  #   time_select("article", "written_on", prompt: { hour: 'Choose hour', minute: 'Choose minute', second: 'Choose seconds' })
         | 
| 313 | 
            +
                  #   time_select("article", "written_on", prompt: { hour: true }) # generic prompt for hours
         | 
| 310 314 | 
             
                  #   time_select("article", "written_on", prompt: true) # generic prompts for all
         | 
| 311 315 | 
             
                  #
         | 
| 312 316 | 
             
                  #   # You can set :ampm option to true which will show the hours as: 12 PM, 01 AM .. 11 PM.
         | 
| 313 | 
            -
                  #   time_select 'game', 'game_time', {ampm: true}
         | 
| 317 | 
            +
                  #   time_select 'game', 'game_time', { ampm: true }
         | 
| 314 318 | 
             
                  #
         | 
| 315 319 | 
             
                  # The selects are prepared for multi-parameter assignment to an Active Record object.
         | 
| 316 320 | 
             
                  #
         | 
| @@ -346,8 +350,8 @@ module ActionView | |
| 346 350 | 
             
                  #   datetime_select("article", "written_on", discard_type: true)
         | 
| 347 351 | 
             
                  #
         | 
| 348 352 | 
             
                  #   # Generates a datetime select with a custom prompt. Use <tt>prompt: true</tt> for generic prompts.
         | 
| 349 | 
            -
                  #   datetime_select("article", "written_on", prompt: {day: 'Choose day', month: 'Choose month', year: 'Choose year'})
         | 
| 350 | 
            -
                  #   datetime_select("article", "written_on", prompt: {hour: true}) # generic prompt for hours
         | 
| 353 | 
            +
                  #   datetime_select("article", "written_on", prompt: { day: 'Choose day', month: 'Choose month', year: 'Choose year' })
         | 
| 354 | 
            +
                  #   datetime_select("article", "written_on", prompt: { hour: true }) # generic prompt for hours
         | 
| 351 355 | 
             
                  #   datetime_select("article", "written_on", prompt: true) # generic prompts for all
         | 
| 352 356 | 
             
                  #
         | 
| 353 357 | 
             
                  # The selects are prepared for multi-parameter assignment to an Active Record object.
         | 
| @@ -397,8 +401,8 @@ module ActionView | |
| 397 401 | 
             
                  #   select_datetime(my_date_time, prefix: 'payday')
         | 
| 398 402 | 
             
                  #
         | 
| 399 403 | 
             
                  #   # Generates a datetime select with a custom prompt. Use <tt>prompt: true</tt> for generic prompts.
         | 
| 400 | 
            -
                  #   select_datetime(my_date_time, prompt: {day: 'Choose day', month: 'Choose month', year: 'Choose year'})
         | 
| 401 | 
            -
                  #   select_datetime(my_date_time, prompt: {hour: true}) # generic prompt for hours
         | 
| 404 | 
            +
                  #   select_datetime(my_date_time, prompt: { day: 'Choose day', month: 'Choose month', year: 'Choose year' })
         | 
| 405 | 
            +
                  #   select_datetime(my_date_time, prompt: { hour: true }) # generic prompt for hours
         | 
| 402 406 | 
             
                  #   select_datetime(my_date_time, prompt: true) # generic prompts for all
         | 
| 403 407 | 
             
                  def select_datetime(datetime = Time.current, options = {}, html_options = {})
         | 
| 404 408 | 
             
                    DateTimeSelector.new(datetime, options, html_options).select_datetime
         | 
| @@ -436,8 +440,8 @@ module ActionView | |
| 436 440 | 
             
                  #   select_date(my_date, prefix: 'payday')
         | 
| 437 441 | 
             
                  #
         | 
| 438 442 | 
             
                  #   # Generates a date select with a custom prompt. Use <tt>prompt: true</tt> for generic prompts.
         | 
| 439 | 
            -
                  #   select_date(my_date, prompt: {day: 'Choose day', month: 'Choose month', year: 'Choose year'})
         | 
| 440 | 
            -
                  #   select_date(my_date, prompt: {hour: true}) # generic prompt for hours
         | 
| 443 | 
            +
                  #   select_date(my_date, prompt: { day: 'Choose day', month: 'Choose month', year: 'Choose year' })
         | 
| 444 | 
            +
                  #   select_date(my_date, prompt: { hour: true }) # generic prompt for hours
         | 
| 441 445 | 
             
                  #   select_date(my_date, prompt: true) # generic prompts for all
         | 
| 442 446 | 
             
                  def select_date(date = Date.current, options = {}, html_options = {})
         | 
| 443 447 | 
             
                    DateTimeSelector.new(date, options, html_options).select_date
         | 
| @@ -476,8 +480,8 @@ module ActionView | |
| 476 480 | 
             
                  #   select_time(my_time, start_hour: 2, end_hour: 14)
         | 
| 477 481 | 
             
                  #
         | 
| 478 482 | 
             
                  #   # Generates a time select with a custom prompt. Use <tt>:prompt</tt> to true for generic prompts.
         | 
| 479 | 
            -
                  #   select_time(my_time, prompt: {day: 'Choose day', month: 'Choose month', year: 'Choose year'})
         | 
| 480 | 
            -
                  #   select_time(my_time, prompt: {hour: true}) # generic prompt for hours
         | 
| 483 | 
            +
                  #   select_time(my_time, prompt: { day: 'Choose day', month: 'Choose month', year: 'Choose year' })
         | 
| 484 | 
            +
                  #   select_time(my_time, prompt: { hour: true }) # generic prompt for hours
         | 
| 481 485 | 
             
                  #   select_time(my_time, prompt: true) # generic prompts for all
         | 
| 482 486 | 
             
                  def select_time(datetime = Time.current, options = {}, html_options = {})
         | 
| 483 487 | 
             
                    DateTimeSelector.new(datetime, options, html_options).select_time
         | 
| @@ -668,8 +672,6 @@ module ActionView | |
| 668 672 | 
             
                  #     <time datetime="2010-11-04T17:55:45+01:00">November 04, 2010 17:55</time>
         | 
| 669 673 | 
             
                  #   time_tag Date.yesterday, 'Yesterday'  # =>
         | 
| 670 674 | 
             
                  #     <time datetime="2010-11-03">Yesterday</time>
         | 
| 671 | 
            -
                  #   time_tag Date.today, pubdate: true  # =>
         | 
| 672 | 
            -
                  #     <time datetime="2010-11-04" pubdate="pubdate">November 04, 2010</time>
         | 
| 673 675 | 
             
                  #   time_tag Date.today, datetime: Date.today.strftime('%G-W%V') # =>
         | 
| 674 676 | 
             
                  #     <time datetime="2010-W44">November 04, 2010</time>
         | 
| 675 677 | 
             
                  #
         | 
| @@ -681,9 +683,8 @@ module ActionView | |
| 681 683 | 
             
                    options  = args.extract_options!
         | 
| 682 684 | 
             
                    format   = options.delete(:format) || :long
         | 
| 683 685 | 
             
                    content  = args.first || I18n.l(date_or_time, format: format)
         | 
| 684 | 
            -
                    datetime = date_or_time.acts_like?(:time) ? date_or_time.xmlschema : date_or_time.iso8601
         | 
| 685 686 |  | 
| 686 | 
            -
                    content_tag("time" | 
| 687 | 
            +
                    content_tag("time", content, options.reverse_merge(datetime: date_or_time.iso8601), &block)
         | 
| 687 688 | 
             
                  end
         | 
| 688 689 |  | 
| 689 690 | 
             
                  private
         | 
| @@ -702,7 +703,7 @@ module ActionView | |
| 702 703 | 
             
                class DateTimeSelector #:nodoc:
         | 
| 703 704 | 
             
                  include ActionView::Helpers::TagHelper
         | 
| 704 705 |  | 
| 705 | 
            -
                  DEFAULT_PREFIX = "date" | 
| 706 | 
            +
                  DEFAULT_PREFIX = "date"
         | 
| 706 707 | 
             
                  POSITION = {
         | 
| 707 708 | 
             
                    year: 1, month: 2, day: 3, hour: 4, minute: 5, second: 6
         | 
| 708 709 | 
             
                  }.freeze
         | 
| @@ -823,7 +824,7 @@ module ActionView | |
| 823 824 | 
             
                      1.upto(12) do |month_number|
         | 
| 824 825 | 
             
                        options = { value: month_number }
         | 
| 825 826 | 
             
                        options[:selected] = "selected" if month == month_number
         | 
| 826 | 
            -
                        month_options << content_tag("option" | 
| 827 | 
            +
                        month_options << content_tag("option", month_name(month_number), options) + "\n"
         | 
| 827 828 | 
             
                      end
         | 
| 828 829 | 
             
                      build_select(:month, month_options.join)
         | 
| 829 830 | 
             
                    end
         | 
| @@ -851,7 +852,7 @@ module ActionView | |
| 851 852 | 
             
                        raise ArgumentError, "There are too many years options to be built. Are you sure you haven't mistyped something? You can provide the :max_years_allowed parameter."
         | 
| 852 853 | 
             
                      end
         | 
| 853 854 |  | 
| 854 | 
            -
                       | 
| 855 | 
            +
                      build_select(:year, build_year_options(val, options))
         | 
| 855 856 | 
             
                    end
         | 
| 856 857 | 
             
                  end
         | 
| 857 858 |  | 
| @@ -934,6 +935,21 @@ module ActionView | |
| 934 935 | 
             
                      end
         | 
| 935 936 | 
             
                    end
         | 
| 936 937 |  | 
| 938 | 
            +
                    # Looks up year names by number.
         | 
| 939 | 
            +
                    #
         | 
| 940 | 
            +
                    #   year_name(1998) # => 1998
         | 
| 941 | 
            +
                    #
         | 
| 942 | 
            +
                    # If the <tt>:year_format</tt> option is passed:
         | 
| 943 | 
            +
                    #
         | 
| 944 | 
            +
                    #   year_name(1998) # => "Heisei 10"
         | 
| 945 | 
            +
                    def year_name(number)
         | 
| 946 | 
            +
                      if year_format_lambda = @options[:year_format]
         | 
| 947 | 
            +
                        year_format_lambda.call(number)
         | 
| 948 | 
            +
                      else
         | 
| 949 | 
            +
                        number
         | 
| 950 | 
            +
                      end
         | 
| 951 | 
            +
                    end
         | 
| 952 | 
            +
             | 
| 937 953 | 
             
                    def date_order
         | 
| 938 954 | 
             
                      @date_order ||= @options[:order] || translated_date_order
         | 
| 939 955 | 
             
                    end
         | 
| @@ -990,7 +1006,35 @@ module ActionView | |
| 990 1006 | 
             
                        tag_options[:selected] = "selected" if selected == i
         | 
| 991 1007 | 
             
                        text = options[:use_two_digit_numbers] ? sprintf("%02d", i) : value
         | 
| 992 1008 | 
             
                        text = options[:ampm] ? AMPM_TRANSLATION[i] : text
         | 
| 993 | 
            -
                        select_options << content_tag("option" | 
| 1009 | 
            +
                        select_options << content_tag("option", text, tag_options)
         | 
| 1010 | 
            +
                      end
         | 
| 1011 | 
            +
             | 
| 1012 | 
            +
                      (select_options.join("\n") + "\n").html_safe
         | 
| 1013 | 
            +
                    end
         | 
| 1014 | 
            +
             | 
| 1015 | 
            +
                    # Build select option HTML for year.
         | 
| 1016 | 
            +
                    # If <tt>year_format</tt> option is not passed
         | 
| 1017 | 
            +
                    #  build_year_options(1998, start: 1998, end: 2000)
         | 
| 1018 | 
            +
                    #  => "<option value="1998" selected="selected">1998</option>
         | 
| 1019 | 
            +
                    #      <option value="1999">1999</option>
         | 
| 1020 | 
            +
                    #      <option value="2000">2000</option>"
         | 
| 1021 | 
            +
                    #
         | 
| 1022 | 
            +
                    # If <tt>year_format</tt> option is passed
         | 
| 1023 | 
            +
                    #  build_year_options(1998, start: 1998, end: 2000, year_format: ->year { "Heisei #{ year - 1988 }" })
         | 
| 1024 | 
            +
                    #  => "<option value="1998" selected="selected">Heisei 10</option>
         | 
| 1025 | 
            +
                    #      <option value="1999">Heisei 11</option>
         | 
| 1026 | 
            +
                    #      <option value="2000">Heisei 12</option>"
         | 
| 1027 | 
            +
                    def build_year_options(selected, options = {})
         | 
| 1028 | 
            +
                      start = options.delete(:start)
         | 
| 1029 | 
            +
                      stop = options.delete(:end)
         | 
| 1030 | 
            +
                      step = options.delete(:step)
         | 
| 1031 | 
            +
             | 
| 1032 | 
            +
                      select_options = []
         | 
| 1033 | 
            +
                      start.step(stop, step) do |value|
         | 
| 1034 | 
            +
                        tag_options = { value: value }
         | 
| 1035 | 
            +
                        tag_options[:selected] = "selected" if selected == value
         | 
| 1036 | 
            +
                        text = year_name(value)
         | 
| 1037 | 
            +
                        select_options << content_tag("option", text, tag_options)
         | 
| 994 1038 | 
             
                      end
         | 
| 995 1039 |  | 
| 996 1040 | 
             
                      (select_options.join("\n") + "\n").html_safe
         | 
| @@ -1009,12 +1053,12 @@ module ActionView | |
| 1009 1053 | 
             
                      select_options[:disabled] = "disabled" if @options[:disabled]
         | 
| 1010 1054 | 
             
                      select_options[:class] = css_class_attribute(type, select_options[:class], @options[:with_css_classes]) if @options[:with_css_classes]
         | 
| 1011 1055 |  | 
| 1012 | 
            -
                      select_html = "\n" | 
| 1013 | 
            -
                      select_html << content_tag("option" | 
| 1056 | 
            +
                      select_html = +"\n"
         | 
| 1057 | 
            +
                      select_html << content_tag("option", "", value: "") + "\n" if @options[:include_blank]
         | 
| 1014 1058 | 
             
                      select_html << prompt_option_tag(type, @options[:prompt]) + "\n" if @options[:prompt]
         | 
| 1015 1059 | 
             
                      select_html << select_options_as_html
         | 
| 1016 1060 |  | 
| 1017 | 
            -
                      (content_tag("select" | 
| 1061 | 
            +
                      (content_tag("select", select_html.html_safe, select_options) + "\n").html_safe
         | 
| 1018 1062 | 
             
                    end
         | 
| 1019 1063 |  | 
| 1020 1064 | 
             
                    # Builds the css class value for the select element
         | 
| @@ -1047,7 +1091,7 @@ module ActionView | |
| 1047 1091 | 
             
                          I18n.translate(:"datetime.prompts.#{type}", locale: @options[:locale])
         | 
| 1048 1092 | 
             
                        end
         | 
| 1049 1093 |  | 
| 1050 | 
            -
                      prompt ? content_tag("option" | 
| 1094 | 
            +
                      prompt ? content_tag("option", prompt, value: "") : ""
         | 
| 1051 1095 | 
             
                    end
         | 
| 1052 1096 |  | 
| 1053 1097 | 
             
                    # Builds hidden input tag for date part and value.
         | 
| @@ -1091,7 +1135,7 @@ module ActionView | |
| 1091 1135 | 
             
                    # Given an ordering of datetime components, create the selection HTML
         | 
| 1092 1136 | 
             
                    # and join them with their appropriate separators.
         | 
| 1093 1137 | 
             
                    def build_selects_from_types(order)
         | 
| 1094 | 
            -
                      select = "" | 
| 1138 | 
            +
                      select = +""
         | 
| 1095 1139 | 
             
                      first_visible = order.find { |type| !@options[:"discard_#{type}"] }
         | 
| 1096 1140 | 
             
                      order.reverse_each do |type|
         | 
| 1097 1141 | 
             
                        separator = separator(type) unless type == first_visible # don't add before first visible field
         |