actionview 6.1.3.2 → 7.0.0.alpha2
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 +99 -262
- data/MIT-LICENSE +1 -1
- data/lib/action_view/base.rb +3 -3
- data/lib/action_view/buffers.rb +2 -2
- data/lib/action_view/cache_expiry.rb +46 -32
- data/lib/action_view/dependency_tracker/erb_tracker.rb +154 -0
- data/lib/action_view/dependency_tracker/ripper_tracker.rb +59 -0
- data/lib/action_view/dependency_tracker.rb +6 -147
- data/lib/action_view/digestor.rb +7 -4
- data/lib/action_view/flows.rb +4 -4
- data/lib/action_view/gem_version.rb +4 -4
- data/lib/action_view/helpers/active_model_helper.rb +1 -1
- data/lib/action_view/helpers/asset_tag_helper.rb +85 -30
- data/lib/action_view/helpers/asset_url_helper.rb +7 -7
- data/lib/action_view/helpers/atom_feed_helper.rb +3 -4
- data/lib/action_view/helpers/cache_helper.rb +51 -3
- data/lib/action_view/helpers/capture_helper.rb +2 -2
- data/lib/action_view/helpers/controller_helper.rb +2 -2
- data/lib/action_view/helpers/csp_helper.rb +1 -1
- data/lib/action_view/helpers/csrf_helper.rb +1 -1
- data/lib/action_view/helpers/date_helper.rb +5 -5
- data/lib/action_view/helpers/debug_helper.rb +3 -1
- data/lib/action_view/helpers/form_helper.rb +72 -12
- data/lib/action_view/helpers/form_options_helper.rb +65 -33
- data/lib/action_view/helpers/form_tag_helper.rb +73 -30
- data/lib/action_view/helpers/javascript_helper.rb +3 -5
- data/lib/action_view/helpers/number_helper.rb +3 -4
- data/lib/action_view/helpers/output_safety_helper.rb +2 -2
- data/lib/action_view/helpers/rendering_helper.rb +1 -1
- data/lib/action_view/helpers/sanitize_helper.rb +2 -2
- data/lib/action_view/helpers/tag_helper.rb +17 -4
- data/lib/action_view/helpers/tags/base.rb +2 -14
- data/lib/action_view/helpers/tags/check_box.rb +1 -1
- data/lib/action_view/helpers/tags/collection_select.rb +1 -1
- data/lib/action_view/helpers/tags/time_field.rb +10 -1
- data/lib/action_view/helpers/tags/weekday_select.rb +27 -0
- data/lib/action_view/helpers/tags.rb +3 -2
- data/lib/action_view/helpers/text_helper.rb +24 -13
- data/lib/action_view/helpers/translation_helper.rb +4 -3
- data/lib/action_view/helpers/url_helper.rb +122 -80
- data/lib/action_view/helpers.rb +25 -25
- data/lib/action_view/lookup_context.rb +33 -52
- data/lib/action_view/model_naming.rb +1 -1
- data/lib/action_view/path_set.rb +16 -22
- data/lib/action_view/railtie.rb +15 -2
- data/lib/action_view/render_parser.rb +188 -0
- data/lib/action_view/renderer/abstract_renderer.rb +2 -2
- data/lib/action_view/renderer/partial_renderer.rb +0 -34
- data/lib/action_view/renderer/renderer.rb +4 -4
- data/lib/action_view/renderer/streaming_template_renderer.rb +3 -3
- data/lib/action_view/renderer/template_renderer.rb +6 -2
- data/lib/action_view/rendering.rb +2 -2
- data/lib/action_view/ripper_ast_parser.rb +198 -0
- data/lib/action_view/routing_url_for.rb +1 -1
- data/lib/action_view/template/error.rb +108 -13
- data/lib/action_view/template/handlers/erb.rb +6 -0
- data/lib/action_view/template/handlers.rb +3 -3
- data/lib/action_view/template/html.rb +3 -3
- data/lib/action_view/template/inline.rb +3 -3
- data/lib/action_view/template/raw_file.rb +3 -3
- data/lib/action_view/template/resolver.rb +84 -311
- data/lib/action_view/template/text.rb +3 -3
- data/lib/action_view/template/types.rb +14 -12
- data/lib/action_view/template.rb +10 -1
- data/lib/action_view/template_details.rb +66 -0
- data/lib/action_view/template_path.rb +64 -0
- data/lib/action_view/test_case.rb +6 -2
- data/lib/action_view/testing/resolvers.rb +11 -12
- data/lib/action_view/unbound_template.rb +33 -7
- data/lib/action_view.rb +3 -4
- data/lib/assets/compiled/rails-ujs.js +2 -2
- metadata +25 -18
data/lib/action_view/digestor.rb
CHANGED
@@ -17,15 +17,16 @@ module ActionView
|
|
17
17
|
if dependencies.nil? || dependencies.empty?
|
18
18
|
cache_key = "#{name}.#{format}"
|
19
19
|
else
|
20
|
-
|
20
|
+
dependencies_suffix = dependencies.flatten.tap(&:compact!).join(".")
|
21
|
+
cache_key = "#{name}.#{format}.#{dependencies_suffix}"
|
21
22
|
end
|
22
23
|
|
23
24
|
# this is a correctly done double-checked locking idiom
|
24
25
|
# (Concurrent::Map's lookups have volatile semantics)
|
25
26
|
finder.digest_cache[cache_key] || @@digest_mutex.synchronize do
|
26
27
|
finder.digest_cache.fetch(cache_key) do # re-check under lock
|
27
|
-
|
28
|
-
root = tree(
|
28
|
+
path = TemplatePath.parse(name)
|
29
|
+
root = tree(path.to_s, finder, path.partial?)
|
29
30
|
dependencies.each do |injected_dep|
|
30
31
|
root.children << Injected.new(injected_dep, nil, nil)
|
31
32
|
end if dependencies
|
@@ -43,7 +44,9 @@ module ActionView
|
|
43
44
|
logical_name = name.gsub(%r|/_|, "/")
|
44
45
|
interpolated = name.include?("#")
|
45
46
|
|
46
|
-
|
47
|
+
path = TemplatePath.parse(name)
|
48
|
+
|
49
|
+
if !interpolated && (template = find_template(finder, path.name, [path.prefix], partial, []))
|
47
50
|
if node = seen[template.identifier] # handle cycles in the tree
|
48
51
|
node
|
49
52
|
else
|
data/lib/action_view/flows.rb
CHANGED
@@ -3,7 +3,7 @@
|
|
3
3
|
require "active_support/core_ext/string/output_safety"
|
4
4
|
|
5
5
|
module ActionView
|
6
|
-
class OutputFlow
|
6
|
+
class OutputFlow # :nodoc:
|
7
7
|
attr_reader :content
|
8
8
|
|
9
9
|
def initialize
|
@@ -17,17 +17,17 @@ module ActionView
|
|
17
17
|
|
18
18
|
# Called by each renderer object to set the layout contents.
|
19
19
|
def set(key, value)
|
20
|
-
@content[key] = ActiveSupport::SafeBuffer.new(value)
|
20
|
+
@content[key] = ActiveSupport::SafeBuffer.new(value.to_s)
|
21
21
|
end
|
22
22
|
|
23
23
|
# Called by content_for
|
24
24
|
def append(key, value)
|
25
|
-
@content[key] << value
|
25
|
+
@content[key] << value.to_s
|
26
26
|
end
|
27
27
|
alias_method :append!, :append
|
28
28
|
end
|
29
29
|
|
30
|
-
class StreamingFlow < OutputFlow
|
30
|
+
class StreamingFlow < OutputFlow # :nodoc:
|
31
31
|
def initialize(view, fiber)
|
32
32
|
@view = view
|
33
33
|
@parent = nil
|
@@ -8,7 +8,7 @@ require "action_view/helpers/tag_helper"
|
|
8
8
|
|
9
9
|
module ActionView
|
10
10
|
# = Action View Asset Tag Helpers
|
11
|
-
module Helpers
|
11
|
+
module Helpers # :nodoc:
|
12
12
|
# This module provides methods for generating HTML that links views to assets such
|
13
13
|
# as images, JavaScripts, stylesheets, and feeds. These methods do not verify
|
14
14
|
# the assets exist before linking to them:
|
@@ -16,14 +16,15 @@ module ActionView
|
|
16
16
|
# image_tag("rails.png")
|
17
17
|
# # => <img src="/assets/rails.png" />
|
18
18
|
# stylesheet_link_tag("application")
|
19
|
-
# # => <link href="/assets/application.css?body=1"
|
19
|
+
# # => <link href="/assets/application.css?body=1" rel="stylesheet" />
|
20
20
|
module AssetTagHelper
|
21
|
-
extend ActiveSupport::Concern
|
22
|
-
|
23
21
|
include AssetUrlHelper
|
24
22
|
include TagHelper
|
25
23
|
|
24
|
+
mattr_accessor :image_loading
|
25
|
+
mattr_accessor :image_decoding
|
26
26
|
mattr_accessor :preload_links_header
|
27
|
+
mattr_accessor :apply_stylesheet_media_default
|
27
28
|
|
28
29
|
# Returns an HTML script tag for each of the +sources+ provided.
|
29
30
|
#
|
@@ -93,11 +94,12 @@ module ActionView
|
|
93
94
|
crossorigin = options.delete("crossorigin")
|
94
95
|
crossorigin = "anonymous" if crossorigin == true
|
95
96
|
integrity = options["integrity"]
|
97
|
+
rel = options["type"] == "module" ? "modulepreload" : "preload"
|
96
98
|
|
97
99
|
sources_tags = sources.uniq.map { |source|
|
98
100
|
href = path_to_javascript(source, path_options)
|
99
|
-
if preload_links_header && !options["defer"]
|
100
|
-
preload_link = "<#{href}>; rel
|
101
|
+
if preload_links_header && !options["defer"] && href.present? && !href.start_with?("data:")
|
102
|
+
preload_link = "<#{href}>; rel=#{rel}; as=script"
|
101
103
|
preload_link += "; crossorigin=#{crossorigin}" unless crossorigin.nil?
|
102
104
|
preload_link += "; integrity=#{integrity}" unless integrity.nil?
|
103
105
|
preload_link += "; nopush" if nopush
|
@@ -120,24 +122,41 @@ module ActionView
|
|
120
122
|
sources_tags
|
121
123
|
end
|
122
124
|
|
123
|
-
# Returns a stylesheet link tag for the sources specified as arguments.
|
124
|
-
#
|
125
|
+
# Returns a stylesheet link tag for the sources specified as arguments.
|
126
|
+
#
|
127
|
+
# When passing paths, the <tt>.css</tt> extension is optional.
|
128
|
+
# If you don't specify an extension, <tt>.css</tt> will be appended automatically.
|
129
|
+
# If you do not want <tt>.css</tt> appended to the path,
|
130
|
+
# set <tt>extname: false</tt> in the options.
|
125
131
|
# You can modify the link attributes by passing a hash as the last argument.
|
126
|
-
# For historical reasons, the 'media' attribute will always be present and defaults
|
127
|
-
# to "screen", so you must explicitly set it to "all" for the stylesheet(s) to
|
128
|
-
# apply to all media types.
|
129
132
|
#
|
130
133
|
# If the server supports Early Hints header links for these assets will be
|
131
134
|
# automatically pushed.
|
132
135
|
#
|
136
|
+
# ==== Options
|
137
|
+
#
|
138
|
+
# * <tt>:extname</tt> - Append an extension to the generated URL unless the extension
|
139
|
+
# already exists. This only applies for relative URLs.
|
140
|
+
# * <tt>:protocol</tt> - Sets the protocol of the generated URL. This option only
|
141
|
+
# applies when a relative URL and +host+ options are provided.
|
142
|
+
# * <tt>:host</tt> - When a relative URL is provided the host is added to the
|
143
|
+
# that path.
|
144
|
+
# * <tt>:skip_pipeline</tt> - This option is used to bypass the asset pipeline
|
145
|
+
# when it is set to true.
|
146
|
+
#
|
147
|
+
# ==== Examples
|
148
|
+
#
|
133
149
|
# stylesheet_link_tag "style"
|
134
|
-
# # => <link href="/assets/style.css"
|
150
|
+
# # => <link href="/assets/style.css" rel="stylesheet" />
|
135
151
|
#
|
136
152
|
# stylesheet_link_tag "style.css"
|
137
|
-
# # => <link href="/assets/style.css"
|
153
|
+
# # => <link href="/assets/style.css" rel="stylesheet" />
|
138
154
|
#
|
139
155
|
# stylesheet_link_tag "http://www.example.com/style.css"
|
140
|
-
# # => <link href="http://www.example.com/style.css"
|
156
|
+
# # => <link href="http://www.example.com/style.css" rel="stylesheet" />
|
157
|
+
#
|
158
|
+
# stylesheet_link_tag "style.less", extname: false, skip_pipeline: true, rel: "stylesheet/less"
|
159
|
+
# # => <link href="/stylesheets/style.less" rel="stylesheet/less">
|
141
160
|
#
|
142
161
|
# stylesheet_link_tag "style", media: "all"
|
143
162
|
# # => <link href="/assets/style.css" media="all" rel="stylesheet" />
|
@@ -146,11 +165,11 @@ module ActionView
|
|
146
165
|
# # => <link href="/assets/style.css" media="print" rel="stylesheet" />
|
147
166
|
#
|
148
167
|
# stylesheet_link_tag "random.styles", "/css/stylish"
|
149
|
-
# # => <link href="/assets/random.styles"
|
150
|
-
# # <link href="/css/stylish.css"
|
168
|
+
# # => <link href="/assets/random.styles" rel="stylesheet" />
|
169
|
+
# # <link href="/css/stylish.css" rel="stylesheet" />
|
151
170
|
def stylesheet_link_tag(*sources)
|
152
171
|
options = sources.extract_options!.stringify_keys
|
153
|
-
path_options = options.extract!("protocol", "host", "skip_pipeline").symbolize_keys
|
172
|
+
path_options = options.extract!("protocol", "extname", "host", "skip_pipeline").symbolize_keys
|
154
173
|
preload_links = []
|
155
174
|
crossorigin = options.delete("crossorigin")
|
156
175
|
crossorigin = "anonymous" if crossorigin == true
|
@@ -159,7 +178,7 @@ module ActionView
|
|
159
178
|
|
160
179
|
sources_tags = sources.uniq.map { |source|
|
161
180
|
href = path_to_stylesheet(source, path_options)
|
162
|
-
if preload_links_header
|
181
|
+
if preload_links_header && href.present? && !href.start_with?("data:")
|
163
182
|
preload_link = "<#{href}>; rel=preload; as=style"
|
164
183
|
preload_link += "; crossorigin=#{crossorigin}" unless crossorigin.nil?
|
165
184
|
preload_link += "; integrity=#{integrity}" unless integrity.nil?
|
@@ -168,10 +187,14 @@ module ActionView
|
|
168
187
|
end
|
169
188
|
tag_options = {
|
170
189
|
"rel" => "stylesheet",
|
171
|
-
"media" => "screen",
|
172
190
|
"crossorigin" => crossorigin,
|
173
191
|
"href" => href
|
174
192
|
}.merge!(options)
|
193
|
+
|
194
|
+
if apply_stylesheet_media_default && tag_options["media"].blank?
|
195
|
+
tag_options["media"] = "screen"
|
196
|
+
end
|
197
|
+
|
175
198
|
tag(:link, tag_options)
|
176
199
|
}.join("\n").html_safe
|
177
200
|
|
@@ -294,7 +317,7 @@ module ActionView
|
|
294
317
|
# # => <link rel="preload" href="/media/audio.ogg" as="audio" type="audio/ogg" />
|
295
318
|
#
|
296
319
|
def preload_link_tag(source, options = {})
|
297
|
-
href =
|
320
|
+
href = path_to_asset(source, skip_pipeline: options.delete(:skip_pipeline))
|
298
321
|
extname = File.extname(source).downcase.delete(".")
|
299
322
|
mime_type = options.delete(:type) || Template::Types[extname]&.to_s
|
300
323
|
as_type = options.delete(:as) || resolve_link_as(extname, mime_type)
|
@@ -382,6 +405,10 @@ module ActionView
|
|
382
405
|
end
|
383
406
|
|
384
407
|
options[:width], options[:height] = extract_dimensions(options.delete(:size)) if options[:size]
|
408
|
+
|
409
|
+
options[:loading] ||= image_loading if image_loading
|
410
|
+
options[:decoding] ||= image_decoding if image_decoding
|
411
|
+
|
385
412
|
tag("img", options)
|
386
413
|
end
|
387
414
|
|
@@ -503,24 +530,52 @@ module ActionView
|
|
503
530
|
end
|
504
531
|
|
505
532
|
def resolve_link_as(extname, mime_type)
|
506
|
-
|
507
|
-
|
508
|
-
|
509
|
-
|
510
|
-
|
511
|
-
"
|
512
|
-
elsif (type = mime_type.to_s.split("/")[0]) && type.in?(%w(audio video font))
|
513
|
-
type
|
533
|
+
case extname
|
534
|
+
when "js" then "script"
|
535
|
+
when "css" then "style"
|
536
|
+
when "vtt" then "track"
|
537
|
+
else
|
538
|
+
mime_type.to_s.split("/").first.presence_in(%w(audio video font image))
|
514
539
|
end
|
515
540
|
end
|
516
541
|
|
517
|
-
|
542
|
+
MAX_HEADER_SIZE = 8_000 # Some HTTP client and proxies have a 8kiB header limit
|
543
|
+
def send_preload_links_header(preload_links, max_header_size: MAX_HEADER_SIZE)
|
544
|
+
return if preload_links.empty?
|
545
|
+
return if response.sending?
|
546
|
+
|
518
547
|
if respond_to?(:request) && request
|
519
548
|
request.send_early_hints("Link" => preload_links.join("\n"))
|
520
549
|
end
|
521
550
|
|
522
551
|
if respond_to?(:response) && response
|
523
|
-
|
552
|
+
header = response.headers["Link"]
|
553
|
+
header = header ? header.dup : +""
|
554
|
+
|
555
|
+
# rindex count characters not bytes, but we assume non-ascii characters
|
556
|
+
# are rare in urls, and we have a 192 bytes margin.
|
557
|
+
last_line_offset = header.rindex("\n")
|
558
|
+
last_line_size = if last_line_offset
|
559
|
+
header.bytesize - last_line_offset
|
560
|
+
else
|
561
|
+
header.bytesize
|
562
|
+
end
|
563
|
+
|
564
|
+
preload_links.each do |link|
|
565
|
+
if link.bytesize + last_line_size + 1 < max_header_size
|
566
|
+
unless header.empty?
|
567
|
+
header << ","
|
568
|
+
last_line_size += 1
|
569
|
+
end
|
570
|
+
else
|
571
|
+
header << "\n"
|
572
|
+
last_line_size = 0
|
573
|
+
end
|
574
|
+
header << link
|
575
|
+
last_line_size += link.bytesize
|
576
|
+
end
|
577
|
+
|
578
|
+
response.headers["Link"] = header
|
524
579
|
end
|
525
580
|
end
|
526
581
|
end
|
@@ -4,7 +4,7 @@ require "zlib"
|
|
4
4
|
|
5
5
|
module ActionView
|
6
6
|
# = Action View Asset URL Helpers
|
7
|
-
module Helpers
|
7
|
+
module Helpers # :nodoc:
|
8
8
|
# This module provides methods for generating asset paths and
|
9
9
|
# URLs.
|
10
10
|
#
|
@@ -31,7 +31,7 @@ module ActionView
|
|
31
31
|
# image_tag("rails.png")
|
32
32
|
# # => <img src="http://assets.example.com/assets/rails.png" />
|
33
33
|
# stylesheet_link_tag("application")
|
34
|
-
# # => <link href="http://assets.example.com/assets/application.css"
|
34
|
+
# # => <link href="http://assets.example.com/assets/application.css" rel="stylesheet" />
|
35
35
|
#
|
36
36
|
# Browsers open a limited number of simultaneous connections to a single
|
37
37
|
# host. The exact number varies by browser and version. This limit may cause
|
@@ -44,7 +44,7 @@ module ActionView
|
|
44
44
|
# image_tag("rails.png")
|
45
45
|
# # => <img src="http://assets0.example.com/assets/rails.png" />
|
46
46
|
# stylesheet_link_tag("application")
|
47
|
-
# # => <link href="http://assets2.example.com/assets/application.css"
|
47
|
+
# # => <link href="http://assets2.example.com/assets/application.css" rel="stylesheet" />
|
48
48
|
#
|
49
49
|
# This may improve the asset loading performance of your application.
|
50
50
|
# It is also possible the combination of additional connection overhead
|
@@ -65,12 +65,12 @@ module ActionView
|
|
65
65
|
# +asset_host+ to a proc like this:
|
66
66
|
#
|
67
67
|
# ActionController::Base.asset_host = Proc.new { |source|
|
68
|
-
# "http://assets#{Digest::
|
68
|
+
# "http://assets#{OpenSSL::Digest::SHA256.hexdigest(source).to_i(16) % 2 + 1}.example.com"
|
69
69
|
# }
|
70
70
|
# image_tag("rails.png")
|
71
71
|
# # => <img src="http://assets1.example.com/assets/rails.png" />
|
72
72
|
# stylesheet_link_tag("application")
|
73
|
-
# # => <link href="http://assets2.example.com/assets/application.css"
|
73
|
+
# # => <link href="http://assets2.example.com/assets/application.css" rel="stylesheet" />
|
74
74
|
#
|
75
75
|
# The example above generates "http://assets1.example.com" and
|
76
76
|
# "http://assets2.example.com". This option is useful for example if
|
@@ -89,7 +89,7 @@ module ActionView
|
|
89
89
|
# image_tag("rails.png")
|
90
90
|
# # => <img src="http://assets.example.com/assets/rails.png" />
|
91
91
|
# stylesheet_link_tag("application")
|
92
|
-
# # => <link href="http://stylesheets.example.com/assets/application.css"
|
92
|
+
# # => <link href="http://stylesheets.example.com/assets/application.css" rel="stylesheet" />
|
93
93
|
#
|
94
94
|
# Alternatively you may ask for a second parameter +request+. That one is
|
95
95
|
# particularly useful for serving assets from an SSL-protected page. The
|
@@ -190,7 +190,7 @@ module ActionView
|
|
190
190
|
return "" if source.blank?
|
191
191
|
return source if URI_REGEXP.match?(source)
|
192
192
|
|
193
|
-
tail, source = source[/([
|
193
|
+
tail, source = source[/([?#].+)$/], source.sub(/([?#].+)$/, "")
|
194
194
|
|
195
195
|
if extname = compute_asset_extname(source, options)
|
196
196
|
source = "#{source}#{extname}"
|
@@ -1,11 +1,10 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require "set"
|
4
|
-
require "active_support/core_ext/symbol/starts_ends_with"
|
5
4
|
|
6
5
|
module ActionView
|
7
6
|
# = Action View Atom Feed Helpers
|
8
|
-
module Helpers
|
7
|
+
module Helpers # :nodoc:
|
9
8
|
module AtomFeedHelper
|
10
9
|
# Adds easy defaults to writing Atom feeds with the Builder template engine (this does not work on ERB or any other
|
11
10
|
# template languages).
|
@@ -127,7 +126,7 @@ module ActionView
|
|
127
126
|
end
|
128
127
|
end
|
129
128
|
|
130
|
-
class AtomBuilder
|
129
|
+
class AtomBuilder # :nodoc:
|
131
130
|
XHTML_TAG_NAMES = %w(content rights title subtitle summary).to_set
|
132
131
|
|
133
132
|
def initialize(xml)
|
@@ -161,7 +160,7 @@ module ActionView
|
|
161
160
|
end
|
162
161
|
end
|
163
162
|
|
164
|
-
class AtomFeedBuilder < AtomBuilder
|
163
|
+
class AtomFeedBuilder < AtomBuilder # :nodoc:
|
165
164
|
def initialize(xml, view, feed_options = {})
|
166
165
|
@xml, @view, @feed_options = xml, view, feed_options
|
167
166
|
end
|
@@ -2,8 +2,10 @@
|
|
2
2
|
|
3
3
|
module ActionView
|
4
4
|
# = Action View Cache Helper
|
5
|
-
module Helpers
|
5
|
+
module Helpers # :nodoc:
|
6
6
|
module CacheHelper
|
7
|
+
class UncacheableFragmentError < StandardError; end
|
8
|
+
|
7
9
|
# This helper exposes a method for caching fragments of a view
|
8
10
|
# rather than an entire action or page. This technique is useful
|
9
11
|
# caching pieces like menus, lists of new topics, static HTML
|
@@ -165,8 +167,10 @@ module ActionView
|
|
165
167
|
# expire the cache.
|
166
168
|
def cache(name = {}, options = {}, &block)
|
167
169
|
if controller.respond_to?(:perform_caching) && controller.perform_caching
|
168
|
-
|
169
|
-
|
170
|
+
CachingRegistry.track_caching do
|
171
|
+
name_options = options.slice(:skip_digest)
|
172
|
+
safe_concat(fragment_for(cache_fragment_name(name, **name_options), options, &block))
|
173
|
+
end
|
170
174
|
else
|
171
175
|
yield
|
172
176
|
end
|
@@ -174,6 +178,34 @@ module ActionView
|
|
174
178
|
nil
|
175
179
|
end
|
176
180
|
|
181
|
+
# Returns whether the current view fragment is within a +cache+ block.
|
182
|
+
#
|
183
|
+
# Useful when certain fragments aren't cacheable:
|
184
|
+
#
|
185
|
+
# <% cache project do %>
|
186
|
+
# <% raise StandardError, "Caching private data!" if caching? %>
|
187
|
+
# <% end %>
|
188
|
+
def caching?
|
189
|
+
CachingRegistry.caching?
|
190
|
+
end
|
191
|
+
|
192
|
+
# Raises +UncacheableFragmentError+ when called from within a +cache+ block.
|
193
|
+
#
|
194
|
+
# Useful to denote helper methods that can't participate in fragment caching:
|
195
|
+
#
|
196
|
+
# def project_name_with_time(project)
|
197
|
+
# uncacheable!
|
198
|
+
# "#{project.name} - #{Time.now}"
|
199
|
+
# end
|
200
|
+
#
|
201
|
+
# # Which will then raise if used within a +cache+ block:
|
202
|
+
# <% cache project do %>
|
203
|
+
# <%= project_name_with_time(project) %>
|
204
|
+
# <% end %>
|
205
|
+
def uncacheable!
|
206
|
+
raise UncacheableFragmentError, "can't be fragment cached" if caching?
|
207
|
+
end
|
208
|
+
|
177
209
|
# Cache fragments of a view if +condition+ is true
|
178
210
|
#
|
179
211
|
# <% cache_if admin?, project do %>
|
@@ -259,6 +291,22 @@ module ActionView
|
|
259
291
|
end
|
260
292
|
controller.write_fragment(name, fragment, options)
|
261
293
|
end
|
294
|
+
|
295
|
+
class CachingRegistry
|
296
|
+
extend ActiveSupport::PerThreadRegistry
|
297
|
+
|
298
|
+
attr_accessor :caching
|
299
|
+
alias caching? caching
|
300
|
+
|
301
|
+
def self.track_caching
|
302
|
+
caching_was = self.caching
|
303
|
+
self.caching = true
|
304
|
+
|
305
|
+
yield
|
306
|
+
ensure
|
307
|
+
self.caching = caching_was
|
308
|
+
end
|
309
|
+
end
|
262
310
|
end
|
263
311
|
end
|
264
312
|
end
|