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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +201 -192
- data/MIT-LICENSE +1 -1
- data/README.rdoc +9 -8
- data/lib/action_view/base.rb +144 -37
- data/lib/action_view/buffers.rb +18 -1
- data/lib/action_view/cache_expiry.rb +53 -0
- data/lib/action_view/context.rb +8 -12
- data/lib/action_view/dependency_tracker.rb +54 -20
- data/lib/action_view/digestor.rb +88 -85
- data/lib/action_view/flows.rb +11 -12
- data/lib/action_view/gem_version.rb +6 -4
- data/lib/action_view/helpers/active_model_helper.rb +16 -11
- data/lib/action_view/helpers/asset_tag_helper.rb +241 -82
- data/lib/action_view/helpers/asset_url_helper.rb +171 -67
- data/lib/action_view/helpers/atom_feed_helper.rb +19 -17
- data/lib/action_view/helpers/cache_helper.rb +112 -42
- data/lib/action_view/helpers/capture_helper.rb +20 -13
- data/lib/action_view/helpers/controller_helper.rb +15 -4
- data/lib/action_view/helpers/csp_helper.rb +26 -0
- data/lib/action_view/helpers/csrf_helper.rb +8 -6
- data/lib/action_view/helpers/date_helper.rb +230 -129
- data/lib/action_view/helpers/debug_helper.rb +7 -6
- data/lib/action_view/helpers/form_helper.rb +755 -129
- data/lib/action_view/helpers/form_options_helper.rb +130 -75
- data/lib/action_view/helpers/form_tag_helper.rb +116 -71
- data/lib/action_view/helpers/javascript_helper.rb +30 -14
- data/lib/action_view/helpers/number_helper.rb +84 -59
- data/lib/action_view/helpers/output_safety_helper.rb +36 -4
- data/lib/action_view/helpers/rendering_helper.rb +11 -8
- data/lib/action_view/helpers/sanitize_helper.rb +30 -31
- data/lib/action_view/helpers/tag_helper.rb +201 -75
- data/lib/action_view/helpers/tags/base.rb +138 -98
- data/lib/action_view/helpers/tags/check_box.rb +20 -19
- data/lib/action_view/helpers/tags/checkable.rb +4 -2
- data/lib/action_view/helpers/tags/collection_check_boxes.rb +12 -34
- data/lib/action_view/helpers/tags/collection_helpers.rb +69 -36
- data/lib/action_view/helpers/tags/collection_radio_buttons.rb +6 -12
- data/lib/action_view/helpers/tags/collection_select.rb +4 -2
- data/lib/action_view/helpers/tags/color_field.rb +4 -3
- data/lib/action_view/helpers/tags/date_field.rb +2 -1
- data/lib/action_view/helpers/tags/date_select.rb +37 -36
- data/lib/action_view/helpers/tags/datetime_field.rb +4 -3
- data/lib/action_view/helpers/tags/datetime_local_field.rb +2 -1
- data/lib/action_view/helpers/tags/datetime_select.rb +2 -0
- data/lib/action_view/helpers/tags/email_field.rb +2 -0
- data/lib/action_view/helpers/tags/file_field.rb +2 -0
- data/lib/action_view/helpers/tags/grouped_collection_select.rb +4 -2
- data/lib/action_view/helpers/tags/hidden_field.rb +2 -0
- data/lib/action_view/helpers/tags/label.rb +3 -2
- data/lib/action_view/helpers/tags/month_field.rb +2 -1
- data/lib/action_view/helpers/tags/number_field.rb +2 -0
- data/lib/action_view/helpers/tags/password_field.rb +3 -1
- data/lib/action_view/helpers/tags/placeholderable.rb +3 -1
- data/lib/action_view/helpers/tags/radio_button.rb +7 -6
- data/lib/action_view/helpers/tags/range_field.rb +2 -0
- data/lib/action_view/helpers/tags/search_field.rb +14 -9
- data/lib/action_view/helpers/tags/select.rb +11 -10
- data/lib/action_view/helpers/tags/tel_field.rb +2 -0
- data/lib/action_view/helpers/tags/text_area.rb +4 -2
- data/lib/action_view/helpers/tags/text_field.rb +8 -8
- data/lib/action_view/helpers/tags/time_field.rb +2 -1
- data/lib/action_view/helpers/tags/time_select.rb +2 -0
- data/lib/action_view/helpers/tags/time_zone_select.rb +3 -1
- data/lib/action_view/helpers/tags/translator.rb +15 -16
- data/lib/action_view/helpers/tags/url_field.rb +2 -0
- data/lib/action_view/helpers/tags/week_field.rb +2 -1
- data/lib/action_view/helpers/tags.rb +3 -1
- data/lib/action_view/helpers/text_helper.rb +56 -38
- data/lib/action_view/helpers/translation_helper.rb +91 -47
- data/lib/action_view/helpers/url_helper.rb +160 -105
- data/lib/action_view/helpers.rb +5 -3
- data/lib/action_view/layouts.rb +65 -61
- data/lib/action_view/log_subscriber.rb +61 -10
- data/lib/action_view/lookup_context.rb +147 -89
- data/lib/action_view/model_naming.rb +3 -1
- data/lib/action_view/path_set.rb +28 -23
- data/lib/action_view/railtie.rb +62 -6
- data/lib/action_view/record_identifier.rb +53 -26
- data/lib/action_view/renderer/abstract_renderer.rb +71 -13
- data/lib/action_view/renderer/partial_renderer/collection_caching.rb +103 -0
- data/lib/action_view/renderer/partial_renderer.rb +239 -225
- data/lib/action_view/renderer/renderer.rb +22 -8
- data/lib/action_view/renderer/streaming_template_renderer.rb +54 -54
- data/lib/action_view/renderer/template_renderer.rb +79 -73
- data/lib/action_view/rendering.rb +68 -44
- data/lib/action_view/routing_url_for.rb +33 -22
- data/lib/action_view/tasks/cache_digests.rake +25 -0
- data/lib/action_view/template/error.rb +44 -29
- data/lib/action_view/template/handlers/builder.rb +12 -13
- data/lib/action_view/template/handlers/erb/erubi.rb +87 -0
- data/lib/action_view/template/handlers/erb.rb +24 -86
- data/lib/action_view/template/handlers/html.rb +11 -0
- data/lib/action_view/template/handlers/raw.rb +4 -4
- data/lib/action_view/template/handlers.rb +38 -8
- data/lib/action_view/template/html.rb +19 -10
- 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 +217 -193
- data/lib/action_view/template/sources/file.rb +17 -0
- data/lib/action_view/template/sources.rb +13 -0
- data/lib/action_view/template/text.rb +11 -10
- data/lib/action_view/template/types.rb +18 -18
- data/lib/action_view/template.rb +146 -90
- data/lib/action_view/test_case.rb +52 -32
- data/lib/action_view/testing/resolvers.rb +46 -34
- data/lib/action_view/unbound_template.rb +31 -0
- data/lib/action_view/version.rb +3 -1
- data/lib/action_view/view_paths.rb +48 -31
- data/lib/action_view.rb +11 -8
- data/lib/assets/compiled/rails-ujs.js +746 -0
- metadata +38 -29
- data/lib/action_view/helpers/record_tag_helper.rb +0 -108
- 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 :
|
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
|
-
|
30
|
+
class RenderedCollection # :nodoc:
|
31
|
+
def self.empty(format)
|
32
|
+
EmptyCollection.new format
|
33
|
+
end
|
29
34
|
|
30
|
-
|
31
|
-
@lookup_context.registered_details.each_with_object({}) do |key, details|
|
32
|
-
value = options[key]
|
35
|
+
attr_reader :rendered_templates
|
33
36
|
|
34
|
-
|
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
|
-
|
39
|
-
|
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
|
-
|
43
|
-
|
44
|
-
|
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
|
-
|
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
|