actionview 6.0.0.beta1 → 6.0.1.rc1
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 +90 -3
- data/README.rdoc +3 -1
- data/lib/action_view.rb +2 -1
- data/lib/action_view/base.rb +107 -10
- data/lib/action_view/cache_expiry.rb +54 -0
- data/lib/action_view/context.rb +0 -5
- data/lib/action_view/digestor.rb +8 -17
- data/lib/action_view/gem_version.rb +2 -2
- data/lib/action_view/helpers/asset_tag_helper.rb +5 -5
- data/lib/action_view/helpers/cache_helper.rb +5 -5
- data/lib/action_view/helpers/csp_helper.rb +4 -2
- data/lib/action_view/helpers/form_helper.rb +2 -2
- data/lib/action_view/helpers/form_options_helper.rb +4 -3
- data/lib/action_view/helpers/form_tag_helper.rb +5 -2
- 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 +10 -16
- data/lib/action_view/helpers/tag_helper.rb +1 -1
- data/lib/action_view/helpers/tags/base.rb +1 -1
- data/lib/action_view/helpers/translation_helper.rb +3 -3
- data/lib/action_view/helpers/url_helper.rb +2 -2
- data/lib/action_view/layouts.rb +5 -5
- data/lib/action_view/lookup_context.rb +69 -27
- data/lib/action_view/path_set.rb +5 -10
- data/lib/action_view/railtie.rb +9 -4
- 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 +27 -20
- data/lib/action_view/renderer/renderer.rb +16 -4
- data/lib/action_view/renderer/streaming_template_renderer.rb +4 -4
- data/lib/action_view/renderer/template_renderer.rb +24 -18
- data/lib/action_view/rendering.rb +46 -27
- data/lib/action_view/template.rb +84 -69
- 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 +5 -5
- 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 +80 -117
- 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/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 +21 -12
- metadata +25 -16
@@ -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)
|
@@ -216,13 +216,13 @@ module ActionView
|
|
216
216
|
end
|
217
217
|
end
|
218
218
|
|
219
|
-
def
|
220
|
-
digest = Digestor.digest(name: virtual_path, finder: lookup_context, dependencies: view_cache_dependencies)
|
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
221
|
|
222
222
|
if digest.present?
|
223
|
-
"#{virtual_path}:#{digest}"
|
223
|
+
"#{template.virtual_path}:#{digest}"
|
224
224
|
else
|
225
|
-
virtual_path
|
225
|
+
template.virtual_path
|
226
226
|
end
|
227
227
|
end
|
228
228
|
|
@@ -234,7 +234,7 @@ module ActionView
|
|
234
234
|
if virtual_path || digest_path
|
235
235
|
name = controller.url_for(name).split("://").last if name.is_a?(Hash)
|
236
236
|
|
237
|
-
digest_path ||=
|
237
|
+
digest_path ||= digest_path_from_template(@current_template)
|
238
238
|
|
239
239
|
[ digest_path, name ]
|
240
240
|
else
|
@@ -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
|
@@ -739,7 +739,7 @@ module ActionView
|
|
739
739
|
# def labelled_form_with(**options, &block)
|
740
740
|
# form_with(**options.merge(builder: LabellingFormBuilder), &block)
|
741
741
|
# end
|
742
|
-
def form_with(model: nil, scope: nil, url: nil, format: nil, **options)
|
742
|
+
def form_with(model: nil, scope: nil, url: nil, format: nil, **options, &block)
|
743
743
|
options[:allow_method_names_outside_object] = true
|
744
744
|
options[:skip_default_ids] = !form_with_generates_ids
|
745
745
|
|
@@ -752,7 +752,7 @@ module ActionView
|
|
752
752
|
|
753
753
|
if block_given?
|
754
754
|
builder = instantiate_builder(scope, model, options)
|
755
|
-
output = capture(builder, &
|
755
|
+
output = capture(builder, &block)
|
756
756
|
options[:multipart] ||= builder.multipart?
|
757
757
|
|
758
758
|
html_options = html_options_for_form_with(url, model, options)
|
@@ -566,9 +566,10 @@ module ActionView
|
|
566
566
|
# an ActiveSupport::TimeZone.
|
567
567
|
#
|
568
568
|
# By default, +model+ is the ActiveSupport::TimeZone constant (which can
|
569
|
-
# be obtained in Active Record as a value object). The
|
570
|
-
#
|
571
|
-
#
|
569
|
+
# be obtained in Active Record as a value object). The +model+ parameter
|
570
|
+
# must respond to +all+ and return an array of objects that represent time
|
571
|
+
# zones; each object must respond to +name+. If a Regexp is given it will
|
572
|
+
# attempt to match the zones using the <code>=~<code> operator.
|
572
573
|
#
|
573
574
|
# NOTE: Only the option tags are returned, you have to wrap this call in
|
574
575
|
# a regular HTML select tag.
|
@@ -24,7 +24,7 @@ module ActionView
|
|
24
24
|
|
25
25
|
mattr_accessor :default_enforce_utf8, default: true
|
26
26
|
|
27
|
-
# Starts a form tag that points the action to a
|
27
|
+
# Starts a form tag that points the action to a URL configured with <tt>url_for_options</tt> just like
|
28
28
|
# ActionController::Base#url_for. The method for the form defaults to POST.
|
29
29
|
#
|
30
30
|
# ==== Options
|
@@ -137,7 +137,8 @@ module ActionView
|
|
137
137
|
html_name = (options[:multiple] == true && !name.to_s.ends_with?("[]")) ? "#{name}[]" : name
|
138
138
|
|
139
139
|
if options.include?(:include_blank)
|
140
|
-
include_blank = options
|
140
|
+
include_blank = options[:include_blank]
|
141
|
+
options = options.except(:include_blank)
|
141
142
|
options_for_blank_options_tag = { value: "" }
|
142
143
|
|
143
144
|
if include_blank == true
|
@@ -165,6 +166,8 @@ module ActionView
|
|
165
166
|
# * <tt>:size</tt> - The number of visible characters that will fit in the input.
|
166
167
|
# * <tt>:maxlength</tt> - The maximum number of characters that the browser will allow the user to enter.
|
167
168
|
# * <tt>:placeholder</tt> - The text contained in the field by default which is removed when the field receives focus.
|
169
|
+
# If set to true, use a translation is found in the current I18n locale
|
170
|
+
# (through helpers.placeholders.<modelname>.<attribute>).
|
168
171
|
# * Any other key creates standard HTML attributes for the tag.
|
169
172
|
#
|
170
173
|
# ==== Examples
|
@@ -38,7 +38,7 @@ module ActionView #:nodoc:
|
|
38
38
|
|
39
39
|
# Converts the array to a comma-separated sentence where the last element is
|
40
40
|
# joined by the connector word. This is the html_safe-aware version of
|
41
|
-
# ActiveSupport's {Array#to_sentence}[
|
41
|
+
# ActiveSupport's {Array#to_sentence}[https://api.rubyonrails.org/classes/Array.html#method-i-to_sentence].
|
42
42
|
#
|
43
43
|
def to_sentence(array, options = {})
|
44
44
|
options.assert_valid_keys(:words_connector, :two_words_connector, :last_word_connector, :locale)
|
@@ -27,10 +27,12 @@ module ActionView
|
|
27
27
|
def render(options = {}, locals = {}, &block)
|
28
28
|
case options
|
29
29
|
when Hash
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
30
|
+
in_rendering_context(options) do |renderer|
|
31
|
+
if block_given?
|
32
|
+
view_renderer.render_partial(self, options.merge(partial: options[:layout]), &block)
|
33
|
+
else
|
34
|
+
view_renderer.render(self, options)
|
35
|
+
end
|
34
36
|
end
|
35
37
|
else
|
36
38
|
view_renderer.render_partial(self, partial: options, locals: locals, &block)
|
@@ -1,6 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require "active_support/core_ext/object/try"
|
4
3
|
require "rails-html-sanitizer"
|
5
4
|
|
6
5
|
module ActionView
|
@@ -17,7 +16,7 @@ module ActionView
|
|
17
16
|
# ASCII, and hex character references to work around these protocol filters.
|
18
17
|
# All special characters will be escaped.
|
19
18
|
#
|
20
|
-
# The default sanitizer is Rails::Html::
|
19
|
+
# The default sanitizer is Rails::Html::SafeListSanitizer. See {Rails HTML
|
21
20
|
# Sanitizers}[https://github.com/rails/rails-html-sanitizer] for more information.
|
22
21
|
#
|
23
22
|
# Custom sanitization rules can also be provided.
|
@@ -80,12 +79,12 @@ module ActionView
|
|
80
79
|
# config.action_view.sanitized_allowed_tags = ['strong', 'em', 'a']
|
81
80
|
# config.action_view.sanitized_allowed_attributes = ['href', 'title']
|
82
81
|
def sanitize(html, options = {})
|
83
|
-
self.class.
|
82
|
+
self.class.safe_list_sanitizer.sanitize(html, options)&.html_safe
|
84
83
|
end
|
85
84
|
|
86
85
|
# Sanitizes a block of CSS code. Used by +sanitize+ when it comes across a style attribute.
|
87
86
|
def sanitize_css(style)
|
88
|
-
self.class.
|
87
|
+
self.class.safe_list_sanitizer.sanitize_css(style)
|
89
88
|
end
|
90
89
|
|
91
90
|
# Strips all HTML tags from +html+, including comments and special characters.
|
@@ -123,20 +122,18 @@ module ActionView
|
|
123
122
|
end
|
124
123
|
|
125
124
|
module ClassMethods #:nodoc:
|
126
|
-
attr_writer :full_sanitizer, :link_sanitizer, :
|
125
|
+
attr_writer :full_sanitizer, :link_sanitizer, :safe_list_sanitizer
|
127
126
|
|
128
|
-
# Vendors the full, link and white list sanitizers.
|
129
|
-
# Provided strictly for compatibility and can be removed in Rails 6.
|
130
127
|
def sanitizer_vendor
|
131
128
|
Rails::Html::Sanitizer
|
132
129
|
end
|
133
130
|
|
134
131
|
def sanitized_allowed_tags
|
135
|
-
|
132
|
+
safe_list_sanitizer.allowed_tags
|
136
133
|
end
|
137
134
|
|
138
135
|
def sanitized_allowed_attributes
|
139
|
-
|
136
|
+
safe_list_sanitizer.allowed_attributes
|
140
137
|
end
|
141
138
|
|
142
139
|
# Gets the Rails::Html::FullSanitizer instance used by +strip_tags+. Replace with
|
@@ -145,7 +142,6 @@ module ActionView
|
|
145
142
|
# class Application < Rails::Application
|
146
143
|
# config.action_view.full_sanitizer = MySpecialSanitizer.new
|
147
144
|
# end
|
148
|
-
#
|
149
145
|
def full_sanitizer
|
150
146
|
@full_sanitizer ||= sanitizer_vendor.full_sanitizer.new
|
151
147
|
end
|
@@ -156,20 +152,18 @@ module ActionView
|
|
156
152
|
# class Application < Rails::Application
|
157
153
|
# config.action_view.link_sanitizer = MySpecialSanitizer.new
|
158
154
|
# end
|
159
|
-
#
|
160
155
|
def link_sanitizer
|
161
156
|
@link_sanitizer ||= sanitizer_vendor.link_sanitizer.new
|
162
157
|
end
|
163
158
|
|
164
|
-
# Gets the Rails::Html::
|
159
|
+
# Gets the Rails::Html::SafeListSanitizer instance used by sanitize and +sanitize_css+.
|
165
160
|
# Replace with any object that responds to +sanitize+.
|
166
161
|
#
|
167
162
|
# class Application < Rails::Application
|
168
|
-
# config.action_view.
|
163
|
+
# config.action_view.safe_list_sanitizer = MySpecialSanitizer.new
|
169
164
|
# end
|
170
|
-
|
171
|
-
|
172
|
-
@white_list_sanitizer ||= sanitizer_vendor.white_list_sanitizer.new
|
165
|
+
def safe_list_sanitizer
|
166
|
+
@safe_list_sanitizer ||= sanitizer_vendor.safe_list_sanitizer.new
|
173
167
|
end
|
174
168
|
end
|
175
169
|
end
|
@@ -88,7 +88,7 @@ module ActionView
|
|
88
88
|
if value.is_a?(Array)
|
89
89
|
value = escape ? safe_join(value, " ") : value.join(" ")
|
90
90
|
else
|
91
|
-
value = escape ? ERB::Util.unwrapped_html_escape(value) : value.to_s.dup
|
91
|
+
value = escape ? ERB::Util.unwrapped_html_escape(value).dup : value.to_s.dup
|
92
92
|
end
|
93
93
|
value.gsub!('"', """)
|
94
94
|
%(#{key}="#{value}")
|
@@ -138,7 +138,7 @@ module ActionView
|
|
138
138
|
end
|
139
139
|
|
140
140
|
def sanitized_value(value)
|
141
|
-
value.to_s.gsub(
|
141
|
+
value.to_s.gsub(/[\s\.]/, "_").gsub(/[^-[[:word:]]]/, "").downcase
|
142
142
|
end
|
143
143
|
|
144
144
|
def select_content_tag(option_tags, options, html_options)
|
@@ -60,7 +60,7 @@ module ActionView
|
|
60
60
|
def translate(key, options = {})
|
61
61
|
options = options.dup
|
62
62
|
if options.has_key?(:default)
|
63
|
-
remaining_defaults = Array(options.delete(:default)).compact
|
63
|
+
remaining_defaults = Array.wrap(options.delete(:default)).compact
|
64
64
|
options[:default] = remaining_defaults unless remaining_defaults.first.kind_of?(Symbol)
|
65
65
|
end
|
66
66
|
|
@@ -114,7 +114,7 @@ module ActionView
|
|
114
114
|
|
115
115
|
# Delegates to <tt>I18n.localize</tt> with no additional functionality.
|
116
116
|
#
|
117
|
-
# See
|
117
|
+
# See https://www.rubydoc.info/github/svenfuchs/i18n/master/I18n/Backend/Base:localize
|
118
118
|
# for more information.
|
119
119
|
def localize(*args)
|
120
120
|
I18n.localize(*args)
|
@@ -138,7 +138,7 @@ module ActionView
|
|
138
138
|
end
|
139
139
|
|
140
140
|
def html_safe_translation_key?(key)
|
141
|
-
/(
|
141
|
+
/(?:_|\b)html\z/.match?(key.to_s)
|
142
142
|
end
|
143
143
|
end
|
144
144
|
end
|
@@ -253,7 +253,7 @@ module ActionView
|
|
253
253
|
# # <input value="New" type="submit" />
|
254
254
|
# # </form>"
|
255
255
|
#
|
256
|
-
# <%= button_to "New",
|
256
|
+
# <%= button_to "New", new_article_path %>
|
257
257
|
# # => "<form method="post" action="/articles/new" class="button_to">
|
258
258
|
# # <input value="New" type="submit" />
|
259
259
|
# # </form>"
|
@@ -553,7 +553,7 @@ module ActionView
|
|
553
553
|
url_string = URI.parser.unescape(url_for(options)).force_encoding(Encoding::BINARY)
|
554
554
|
|
555
555
|
# We ignore any extra parameters in the request_uri if the
|
556
|
-
# submitted
|
556
|
+
# submitted URL doesn't have any either. This lets the function
|
557
557
|
# work with things like ?order=asc
|
558
558
|
# the behaviour can be disabled with check_parameters: true
|
559
559
|
request_uri = url_string.index("?") || check_parameters ? request.fullpath : request.path
|
data/lib/action_view/layouts.rb
CHANGED
@@ -322,7 +322,7 @@ module ActionView
|
|
322
322
|
end
|
323
323
|
|
324
324
|
class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
325
|
-
def _layout(formats)
|
325
|
+
def _layout(lookup_context, formats)
|
326
326
|
if _conditional_layout?
|
327
327
|
#{layout_definition}
|
328
328
|
else
|
@@ -388,8 +388,8 @@ module ActionView
|
|
388
388
|
case name
|
389
389
|
when String then _normalize_layout(name)
|
390
390
|
when Proc then name
|
391
|
-
when true then Proc.new { |formats| _default_layout(formats, true) }
|
392
|
-
when :default then Proc.new { |formats| _default_layout(formats, false) }
|
391
|
+
when true then Proc.new { |lookup_context, formats| _default_layout(lookup_context, formats, true) }
|
392
|
+
when :default then Proc.new { |lookup_context, formats| _default_layout(lookup_context, formats, false) }
|
393
393
|
when false, nil then nil
|
394
394
|
else
|
395
395
|
raise ArgumentError,
|
@@ -411,9 +411,9 @@ module ActionView
|
|
411
411
|
#
|
412
412
|
# ==== Returns
|
413
413
|
# * <tt>template</tt> - The template object for the default layout (or +nil+)
|
414
|
-
def _default_layout(formats, require_layout = false)
|
414
|
+
def _default_layout(lookup_context, formats, require_layout = false)
|
415
415
|
begin
|
416
|
-
value = _layout(formats) if action_has_layout?
|
416
|
+
value = _layout(lookup_context, formats) if action_has_layout?
|
417
417
|
rescue NameError => e
|
418
418
|
raise e, "Could not render layout: #{e.message}"
|
419
419
|
end
|
@@ -3,6 +3,7 @@
|
|
3
3
|
require "concurrent/map"
|
4
4
|
require "active_support/core_ext/module/remove_method"
|
5
5
|
require "active_support/core_ext/module/attribute_accessors"
|
6
|
+
require "active_support/deprecation"
|
6
7
|
require "action_view/template/resolver"
|
7
8
|
|
8
9
|
module ActionView
|
@@ -15,6 +16,8 @@ module ActionView
|
|
15
16
|
# only once during the request, it speeds up all cache accesses.
|
16
17
|
class LookupContext #:nodoc:
|
17
18
|
attr_accessor :prefixes, :rendered_format
|
19
|
+
deprecate :rendered_format
|
20
|
+
deprecate :rendered_format=
|
18
21
|
|
19
22
|
mattr_accessor :fallbacks, default: FallbackFileSystemResolver.instances
|
20
23
|
|
@@ -57,21 +60,36 @@ module ActionView
|
|
57
60
|
alias :eql? :equal?
|
58
61
|
|
59
62
|
@details_keys = Concurrent::Map.new
|
63
|
+
@digest_cache = Concurrent::Map.new
|
60
64
|
|
61
|
-
def self.
|
65
|
+
def self.digest_cache(details)
|
66
|
+
@digest_cache[details_cache_key(details)] ||= Concurrent::Map.new
|
67
|
+
end
|
68
|
+
|
69
|
+
def self.details_cache_key(details)
|
62
70
|
if details[:formats]
|
63
71
|
details = details.dup
|
64
72
|
details[:formats] &= Template::Types.symbols
|
65
73
|
end
|
66
|
-
@details_keys[details] ||=
|
74
|
+
@details_keys[details] ||= Object.new
|
67
75
|
end
|
68
76
|
|
69
77
|
def self.clear
|
78
|
+
ActionView::ViewPaths.all_view_paths.each do |path_set|
|
79
|
+
path_set.each(&:clear_cache)
|
80
|
+
end
|
81
|
+
ActionView::LookupContext.fallbacks.each(&:clear_cache)
|
82
|
+
@view_context_class = nil
|
70
83
|
@details_keys.clear
|
84
|
+
@digest_cache.clear
|
71
85
|
end
|
72
86
|
|
73
87
|
def self.digest_caches
|
74
|
-
@
|
88
|
+
@digest_cache.values
|
89
|
+
end
|
90
|
+
|
91
|
+
def self.view_context_class(klass)
|
92
|
+
@view_context_class ||= klass.with_empty_template_cache
|
75
93
|
end
|
76
94
|
end
|
77
95
|
|
@@ -82,7 +100,7 @@ module ActionView
|
|
82
100
|
# Calculate the details key. Remove the handlers from calculation to improve performance
|
83
101
|
# since the user cannot modify it explicitly.
|
84
102
|
def details_key #:nodoc:
|
85
|
-
@details_key ||= DetailsKey.
|
103
|
+
@details_key ||= DetailsKey.details_cache_key(@details) if @cache
|
86
104
|
end
|
87
105
|
|
88
106
|
# Temporary skip passing the details_key forward.
|
@@ -96,7 +114,8 @@ module ActionView
|
|
96
114
|
private
|
97
115
|
|
98
116
|
def _set_detail(key, value) # :doc:
|
99
|
-
@details = @details.dup if @details_key
|
117
|
+
@details = @details.dup if @digest_cache || @details_key
|
118
|
+
@digest_cache = nil
|
100
119
|
@details_key = nil
|
101
120
|
@details[key] = value
|
102
121
|
end
|
@@ -106,20 +125,13 @@ module ActionView
|
|
106
125
|
module ViewPaths
|
107
126
|
attr_reader :view_paths, :html_fallback_for_js
|
108
127
|
|
109
|
-
# Whenever setting view paths, makes a copy so that we can manipulate them in
|
110
|
-
# instance objects as we wish.
|
111
|
-
def view_paths=(paths)
|
112
|
-
@view_paths = ActionView::PathSet.new(Array(paths))
|
113
|
-
end
|
114
|
-
|
115
128
|
def find(name, prefixes = [], partial = false, keys = [], options = {})
|
116
129
|
@view_paths.find(*args_for_lookup(name, prefixes, partial, keys, options))
|
117
130
|
end
|
118
131
|
alias :find_template :find
|
119
132
|
|
120
|
-
|
121
|
-
|
122
|
-
end
|
133
|
+
alias :find_file :find
|
134
|
+
deprecate :find_file
|
123
135
|
|
124
136
|
def find_all(name, prefixes = [], partial = false, keys = [], options = {})
|
125
137
|
@view_paths.find_all(*args_for_lookup(name, prefixes, partial, keys, options))
|
@@ -138,19 +150,34 @@ module ActionView
|
|
138
150
|
# Adds fallbacks to the view paths. Useful in cases when you are rendering
|
139
151
|
# a :file.
|
140
152
|
def with_fallbacks
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
153
|
+
view_paths = build_view_paths((@view_paths.paths + self.class.fallbacks).uniq)
|
154
|
+
|
155
|
+
if block_given?
|
156
|
+
ActiveSupport::Deprecation.warn <<~eowarn.squish
|
157
|
+
Calling `with_fallbacks` with a block is deprecated. Call methods on
|
158
|
+
the lookup context returned by `with_fallbacks` instead.
|
159
|
+
eowarn
|
160
|
+
|
161
|
+
begin
|
162
|
+
_view_paths = @view_paths
|
163
|
+
@view_paths = view_paths
|
164
|
+
yield
|
165
|
+
ensure
|
166
|
+
@view_paths = _view_paths
|
167
|
+
end
|
168
|
+
else
|
169
|
+
ActionView::LookupContext.new(view_paths, @details, @prefixes)
|
146
170
|
end
|
147
|
-
yield
|
148
|
-
ensure
|
149
|
-
added_resolvers.times { view_paths.pop }
|
150
171
|
end
|
151
172
|
|
152
173
|
private
|
153
174
|
|
175
|
+
# Whenever setting view paths, makes a copy so that we can manipulate them in
|
176
|
+
# instance objects as we wish.
|
177
|
+
def build_view_paths(paths)
|
178
|
+
ActionView::PathSet.new(Array(paths))
|
179
|
+
end
|
180
|
+
|
154
181
|
def args_for_lookup(name, prefixes, partial, keys, details_options)
|
155
182
|
name, prefixes = normalize_name(name, prefixes)
|
156
183
|
details, details_key = detail_args_for(details_options)
|
@@ -163,7 +190,7 @@ module ActionView
|
|
163
190
|
user_details = @details.merge(options)
|
164
191
|
|
165
192
|
if @cache
|
166
|
-
details_key = DetailsKey.
|
193
|
+
details_key = DetailsKey.details_cache_key(user_details)
|
167
194
|
else
|
168
195
|
details_key = nil
|
169
196
|
end
|
@@ -190,7 +217,7 @@ module ActionView
|
|
190
217
|
end
|
191
218
|
|
192
219
|
if @cache
|
193
|
-
[details, DetailsKey.
|
220
|
+
[details, DetailsKey.details_cache_key(details)]
|
194
221
|
else
|
195
222
|
[details, nil]
|
196
223
|
end
|
@@ -221,16 +248,23 @@ module ActionView
|
|
221
248
|
|
222
249
|
def initialize(view_paths, details = {}, prefixes = [])
|
223
250
|
@details_key = nil
|
251
|
+
@digest_cache = nil
|
224
252
|
@cache = true
|
225
253
|
@prefixes = prefixes
|
226
|
-
@rendered_format = nil
|
227
254
|
|
228
255
|
@details = initialize_details({}, details)
|
229
|
-
|
256
|
+
@view_paths = build_view_paths(view_paths)
|
230
257
|
end
|
231
258
|
|
232
259
|
def digest_cache
|
233
|
-
|
260
|
+
@digest_cache ||= DetailsKey.digest_cache(@details)
|
261
|
+
end
|
262
|
+
|
263
|
+
def with_prepended_formats(formats)
|
264
|
+
details = @details.dup
|
265
|
+
details[:formats] = formats
|
266
|
+
|
267
|
+
self.class.new(@view_paths, details, @prefixes)
|
234
268
|
end
|
235
269
|
|
236
270
|
def initialize_details(target, details)
|
@@ -245,7 +279,15 @@ module ActionView
|
|
245
279
|
# add :html as fallback to :js.
|
246
280
|
def formats=(values)
|
247
281
|
if values
|
282
|
+
values = values.dup
|
248
283
|
values.concat(default_formats) if values.delete "*/*"
|
284
|
+
values.uniq!
|
285
|
+
|
286
|
+
invalid_values = (values - Template::Types.symbols)
|
287
|
+
unless invalid_values.empty?
|
288
|
+
raise ArgumentError, "Invalid formats: #{invalid_values.map(&:inspect).join(", ")}"
|
289
|
+
end
|
290
|
+
|
249
291
|
if values == [:js]
|
250
292
|
values << :html
|
251
293
|
@html_fallback_for_js = true
|