actionview 4.2.11.1 → 6.0.4

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of actionview might be problematic. Click here for more details.

Files changed (114) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +201 -192
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +9 -8
  5. data/lib/action_view/base.rb +144 -37
  6. data/lib/action_view/buffers.rb +18 -1
  7. data/lib/action_view/cache_expiry.rb +53 -0
  8. data/lib/action_view/context.rb +8 -12
  9. data/lib/action_view/dependency_tracker.rb +54 -20
  10. data/lib/action_view/digestor.rb +88 -85
  11. data/lib/action_view/flows.rb +11 -12
  12. data/lib/action_view/gem_version.rb +6 -4
  13. data/lib/action_view/helpers/active_model_helper.rb +16 -11
  14. data/lib/action_view/helpers/asset_tag_helper.rb +241 -82
  15. data/lib/action_view/helpers/asset_url_helper.rb +171 -67
  16. data/lib/action_view/helpers/atom_feed_helper.rb +19 -17
  17. data/lib/action_view/helpers/cache_helper.rb +112 -42
  18. data/lib/action_view/helpers/capture_helper.rb +20 -13
  19. data/lib/action_view/helpers/controller_helper.rb +15 -4
  20. data/lib/action_view/helpers/csp_helper.rb +26 -0
  21. data/lib/action_view/helpers/csrf_helper.rb +8 -6
  22. data/lib/action_view/helpers/date_helper.rb +230 -129
  23. data/lib/action_view/helpers/debug_helper.rb +7 -6
  24. data/lib/action_view/helpers/form_helper.rb +755 -129
  25. data/lib/action_view/helpers/form_options_helper.rb +130 -75
  26. data/lib/action_view/helpers/form_tag_helper.rb +116 -71
  27. data/lib/action_view/helpers/javascript_helper.rb +30 -14
  28. data/lib/action_view/helpers/number_helper.rb +84 -59
  29. data/lib/action_view/helpers/output_safety_helper.rb +36 -4
  30. data/lib/action_view/helpers/rendering_helper.rb +11 -8
  31. data/lib/action_view/helpers/sanitize_helper.rb +30 -31
  32. data/lib/action_view/helpers/tag_helper.rb +201 -75
  33. data/lib/action_view/helpers/tags/base.rb +138 -98
  34. data/lib/action_view/helpers/tags/check_box.rb +20 -19
  35. data/lib/action_view/helpers/tags/checkable.rb +4 -2
  36. data/lib/action_view/helpers/tags/collection_check_boxes.rb +12 -34
  37. data/lib/action_view/helpers/tags/collection_helpers.rb +69 -36
  38. data/lib/action_view/helpers/tags/collection_radio_buttons.rb +6 -12
  39. data/lib/action_view/helpers/tags/collection_select.rb +4 -2
  40. data/lib/action_view/helpers/tags/color_field.rb +4 -3
  41. data/lib/action_view/helpers/tags/date_field.rb +2 -1
  42. data/lib/action_view/helpers/tags/date_select.rb +37 -36
  43. data/lib/action_view/helpers/tags/datetime_field.rb +4 -3
  44. data/lib/action_view/helpers/tags/datetime_local_field.rb +2 -1
  45. data/lib/action_view/helpers/tags/datetime_select.rb +2 -0
  46. data/lib/action_view/helpers/tags/email_field.rb +2 -0
  47. data/lib/action_view/helpers/tags/file_field.rb +2 -0
  48. data/lib/action_view/helpers/tags/grouped_collection_select.rb +4 -2
  49. data/lib/action_view/helpers/tags/hidden_field.rb +2 -0
  50. data/lib/action_view/helpers/tags/label.rb +3 -2
  51. data/lib/action_view/helpers/tags/month_field.rb +2 -1
  52. data/lib/action_view/helpers/tags/number_field.rb +2 -0
  53. data/lib/action_view/helpers/tags/password_field.rb +3 -1
  54. data/lib/action_view/helpers/tags/placeholderable.rb +3 -1
  55. data/lib/action_view/helpers/tags/radio_button.rb +7 -6
  56. data/lib/action_view/helpers/tags/range_field.rb +2 -0
  57. data/lib/action_view/helpers/tags/search_field.rb +14 -9
  58. data/lib/action_view/helpers/tags/select.rb +11 -10
  59. data/lib/action_view/helpers/tags/tel_field.rb +2 -0
  60. data/lib/action_view/helpers/tags/text_area.rb +4 -2
  61. data/lib/action_view/helpers/tags/text_field.rb +8 -8
  62. data/lib/action_view/helpers/tags/time_field.rb +2 -1
  63. data/lib/action_view/helpers/tags/time_select.rb +2 -0
  64. data/lib/action_view/helpers/tags/time_zone_select.rb +3 -1
  65. data/lib/action_view/helpers/tags/translator.rb +15 -16
  66. data/lib/action_view/helpers/tags/url_field.rb +2 -0
  67. data/lib/action_view/helpers/tags/week_field.rb +2 -1
  68. data/lib/action_view/helpers/tags.rb +3 -1
  69. data/lib/action_view/helpers/text_helper.rb +56 -38
  70. data/lib/action_view/helpers/translation_helper.rb +91 -47
  71. data/lib/action_view/helpers/url_helper.rb +160 -105
  72. data/lib/action_view/helpers.rb +5 -3
  73. data/lib/action_view/layouts.rb +65 -61
  74. data/lib/action_view/log_subscriber.rb +61 -10
  75. data/lib/action_view/lookup_context.rb +147 -89
  76. data/lib/action_view/model_naming.rb +3 -1
  77. data/lib/action_view/path_set.rb +28 -23
  78. data/lib/action_view/railtie.rb +62 -6
  79. data/lib/action_view/record_identifier.rb +53 -26
  80. data/lib/action_view/renderer/abstract_renderer.rb +71 -13
  81. data/lib/action_view/renderer/partial_renderer/collection_caching.rb +103 -0
  82. data/lib/action_view/renderer/partial_renderer.rb +239 -225
  83. data/lib/action_view/renderer/renderer.rb +22 -8
  84. data/lib/action_view/renderer/streaming_template_renderer.rb +54 -54
  85. data/lib/action_view/renderer/template_renderer.rb +79 -73
  86. data/lib/action_view/rendering.rb +68 -44
  87. data/lib/action_view/routing_url_for.rb +33 -22
  88. data/lib/action_view/tasks/cache_digests.rake +25 -0
  89. data/lib/action_view/template/error.rb +44 -29
  90. data/lib/action_view/template/handlers/builder.rb +12 -13
  91. data/lib/action_view/template/handlers/erb/erubi.rb +87 -0
  92. data/lib/action_view/template/handlers/erb.rb +24 -86
  93. data/lib/action_view/template/handlers/html.rb +11 -0
  94. data/lib/action_view/template/handlers/raw.rb +4 -4
  95. data/lib/action_view/template/handlers.rb +38 -8
  96. data/lib/action_view/template/html.rb +19 -10
  97. data/lib/action_view/template/inline.rb +22 -0
  98. data/lib/action_view/template/raw_file.rb +28 -0
  99. data/lib/action_view/template/resolver.rb +217 -193
  100. data/lib/action_view/template/sources/file.rb +17 -0
  101. data/lib/action_view/template/sources.rb +13 -0
  102. data/lib/action_view/template/text.rb +11 -10
  103. data/lib/action_view/template/types.rb +18 -18
  104. data/lib/action_view/template.rb +146 -90
  105. data/lib/action_view/test_case.rb +52 -32
  106. data/lib/action_view/testing/resolvers.rb +46 -34
  107. data/lib/action_view/unbound_template.rb +31 -0
  108. data/lib/action_view/version.rb +3 -1
  109. data/lib/action_view/view_paths.rb +48 -31
  110. data/lib/action_view.rb +11 -8
  111. data/lib/assets/compiled/rails-ujs.js +746 -0
  112. metadata +38 -29
  113. data/lib/action_view/helpers/record_tag_helper.rb +0 -108
  114. data/lib/action_view/tasks/dependencies.rake +0 -23
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActionView
2
4
  # This class defines the interface for a renderer. Each class that
3
5
  # subclasses +AbstractRenderer+ is used by the base +Renderer+ class to
@@ -15,7 +17,7 @@ module ActionView
15
17
  # that new object is called in turn. This abstracts the setup and rendering
16
18
  # into a separate classes for partials and templates.
17
19
  class AbstractRenderer #:nodoc:
18
- delegate :find_template, :find_file, :template_exists?, :with_fallbacks, :with_layout_format, :formats, :to => :@lookup_context
20
+ delegate :template_exists?, :any_templates?, :formats, to: :@lookup_context
19
21
 
20
22
  def initialize(lookup_context)
21
23
  @lookup_context = lookup_context
@@ -25,25 +27,81 @@ module ActionView
25
27
  raise NotImplementedError
26
28
  end
27
29
 
28
- protected
30
+ class RenderedCollection # :nodoc:
31
+ def self.empty(format)
32
+ EmptyCollection.new format
33
+ end
29
34
 
30
- def extract_details(options)
31
- @lookup_context.registered_details.each_with_object({}) do |key, details|
32
- value = options[key]
35
+ attr_reader :rendered_templates
33
36
 
34
- details[key] = Array(value) if value
37
+ def initialize(rendered_templates, spacer)
38
+ @rendered_templates = rendered_templates
39
+ @spacer = spacer
40
+ end
41
+
42
+ def body
43
+ @rendered_templates.map(&:body).join(@spacer.body).html_safe
44
+ end
45
+
46
+ def format
47
+ rendered_templates.first.format
35
48
  end
36
- end
37
49
 
38
- def instrument(name, options={})
39
- ActiveSupport::Notifications.instrument("render_#{name}.action_view", options){ yield }
50
+ class EmptyCollection
51
+ attr_reader :format
52
+
53
+ def initialize(format)
54
+ @format = format
55
+ end
56
+
57
+ def body; nil; end
58
+ end
40
59
  end
41
60
 
42
- def prepend_formats(formats)
43
- formats = Array(formats)
44
- return if formats.empty? || @lookup_context.html_fallback_for_js
61
+ class RenderedTemplate # :nodoc:
62
+ attr_reader :body, :layout, :template
63
+
64
+ def initialize(body, layout, template)
65
+ @body = body
66
+ @layout = layout
67
+ @template = template
68
+ end
69
+
70
+ def format
71
+ template.format
72
+ end
45
73
 
46
- @lookup_context.formats = formats | @lookup_context.formats
74
+ EMPTY_SPACER = Struct.new(:body).new
47
75
  end
76
+
77
+ private
78
+ def extract_details(options) # :doc:
79
+ @lookup_context.registered_details.each_with_object({}) do |key, details|
80
+ value = options[key]
81
+
82
+ details[key] = Array(value) if value
83
+ end
84
+ end
85
+
86
+ def instrument(name, **options) # :doc:
87
+ ActiveSupport::Notifications.instrument("render_#{name}.action_view", options) do |payload|
88
+ yield payload
89
+ end
90
+ end
91
+
92
+ def prepend_formats(formats) # :doc:
93
+ formats = Array(formats)
94
+ return if formats.empty? || @lookup_context.html_fallback_for_js
95
+
96
+ @lookup_context.formats = formats | @lookup_context.formats
97
+ end
98
+
99
+ def build_rendered_template(content, template, layout = nil)
100
+ RenderedTemplate.new content, layout, template
101
+ end
102
+
103
+ def build_rendered_collection(templates, spacer)
104
+ RenderedCollection.new templates, spacer
105
+ end
48
106
  end
49
107
  end
@@ -0,0 +1,103 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActionView
4
+ module CollectionCaching # :nodoc:
5
+ extend ActiveSupport::Concern
6
+
7
+ included do
8
+ # Fallback cache store if Action View is used without Rails.
9
+ # Otherwise overridden in Railtie to use Rails.cache.
10
+ mattr_accessor :collection_cache, default: ActiveSupport::Cache::MemoryStore.new
11
+ end
12
+
13
+ private
14
+ def cache_collection_render(instrumentation_payload, view, template)
15
+ return yield unless @options[:cached] && view.controller.respond_to?(:perform_caching) && view.controller.perform_caching
16
+
17
+ # Result is a hash with the key represents the
18
+ # key used for cache lookup and the value is the item
19
+ # on which the partial is being rendered
20
+ keyed_collection, ordered_keys = collection_by_cache_keys(view, template)
21
+
22
+ # Pull all partials from cache
23
+ # Result is a hash, key matches the entry in
24
+ # `keyed_collection` where the cache was retrieved and the
25
+ # value is the value that was present in the cache
26
+ cached_partials = collection_cache.read_multi(*keyed_collection.keys)
27
+ instrumentation_payload[:cache_hits] = cached_partials.size
28
+
29
+ # Extract the items for the keys that are not found
30
+ # Set the uncached values to instance variable @collection
31
+ # which is used by the caller
32
+ @collection = keyed_collection.reject { |key, _| cached_partials.key?(key) }.values
33
+
34
+ # If all elements are already in cache then
35
+ # rendered partials will be an empty array
36
+ #
37
+ # If the cache is missing elements then
38
+ # the block will be called against the remaining items
39
+ # in the @collection.
40
+ rendered_partials = @collection.empty? ? [] : yield
41
+
42
+ index = 0
43
+ keyed_partials = fetch_or_cache_partial(cached_partials, template, order_by: keyed_collection.each_key) do
44
+ # This block is called once
45
+ # for every cache miss while preserving order.
46
+ rendered_partials[index].tap { index += 1 }
47
+ end
48
+
49
+ ordered_keys.map do |key|
50
+ keyed_partials[key]
51
+ end
52
+ end
53
+
54
+ def callable_cache_key?
55
+ @options[:cached].respond_to?(:call)
56
+ end
57
+
58
+ def collection_by_cache_keys(view, template)
59
+ seed = callable_cache_key? ? @options[:cached] : ->(i) { i }
60
+
61
+ digest_path = view.digest_path_from_template(template)
62
+
63
+ @collection.each_with_object([{}, []]) do |item, (hash, ordered_keys)|
64
+ key = expanded_cache_key(seed.call(item), view, template, digest_path)
65
+ ordered_keys << key
66
+ hash[key] = item
67
+ end
68
+ end
69
+
70
+ def expanded_cache_key(key, view, template, digest_path)
71
+ key = view.combined_fragment_cache_key(view.cache_fragment_name(key, virtual_path: template.virtual_path, digest_path: digest_path))
72
+ key.frozen? ? key.dup : key # #read_multi & #write may require mutability, Dalli 2.6.0.
73
+ end
74
+
75
+ # `order_by` is an enumerable object containing keys of the cache,
76
+ # all keys are passed in whether found already or not.
77
+ #
78
+ # `cached_partials` is a hash. If the value exists
79
+ # it represents the rendered partial from the cache
80
+ # otherwise `Hash#fetch` will take the value of its block.
81
+ #
82
+ # This method expects a block that will return the rendered
83
+ # partial. An example is to render all results
84
+ # for each element that was not found in the cache and store it as an array.
85
+ # Order it so that the first empty cache element in `cached_partials`
86
+ # corresponds to the first element in `rendered_partials`.
87
+ #
88
+ # If the partial is not already cached it will also be
89
+ # written back to the underlying cache store.
90
+ def fetch_or_cache_partial(cached_partials, template, order_by:)
91
+ order_by.each_with_object({}) do |cache_key, hash|
92
+ hash[cache_key] =
93
+ if content = cached_partials[cache_key]
94
+ build_rendered_template(content, template)
95
+ else
96
+ yield.tap do |rendered_partial|
97
+ collection_cache.write(cache_key, rendered_partial.body)
98
+ end
99
+ end
100
+ end
101
+ end
102
+ end
103
+ end