actionview 5.2.8.1 → 6.0.6.1

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 (87) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +280 -94
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +5 -3
  5. data/lib/action_view/base.rb +108 -11
  6. data/lib/action_view/buffers.rb +15 -0
  7. data/lib/action_view/cache_expiry.rb +53 -0
  8. data/lib/action_view/context.rb +5 -9
  9. data/lib/action_view/digestor.rb +12 -20
  10. data/lib/action_view/flows.rb +0 -1
  11. data/lib/action_view/gem_version.rb +3 -3
  12. data/lib/action_view/helpers/active_model_helper.rb +0 -1
  13. data/lib/action_view/helpers/asset_tag_helper.rb +8 -31
  14. data/lib/action_view/helpers/asset_url_helper.rb +4 -3
  15. data/lib/action_view/helpers/cache_helper.rb +19 -12
  16. data/lib/action_view/helpers/capture_helper.rb +4 -0
  17. data/lib/action_view/helpers/csp_helper.rb +4 -2
  18. data/lib/action_view/helpers/csrf_helper.rb +1 -1
  19. data/lib/action_view/helpers/date_helper.rb +70 -27
  20. data/lib/action_view/helpers/form_helper.rb +240 -8
  21. data/lib/action_view/helpers/form_options_helper.rb +27 -18
  22. data/lib/action_view/helpers/form_tag_helper.rb +17 -15
  23. data/lib/action_view/helpers/javascript_helper.rb +9 -8
  24. data/lib/action_view/helpers/number_helper.rb +8 -2
  25. data/lib/action_view/helpers/output_safety_helper.rb +1 -1
  26. data/lib/action_view/helpers/rendering_helper.rb +6 -4
  27. data/lib/action_view/helpers/sanitize_helper.rb +12 -18
  28. data/lib/action_view/helpers/tag_helper.rb +8 -7
  29. data/lib/action_view/helpers/tags/base.rb +9 -6
  30. data/lib/action_view/helpers/tags/check_box.rb +0 -1
  31. data/lib/action_view/helpers/tags/collection_check_boxes.rb +0 -1
  32. data/lib/action_view/helpers/tags/collection_helpers.rb +0 -1
  33. data/lib/action_view/helpers/tags/collection_radio_buttons.rb +0 -1
  34. data/lib/action_view/helpers/tags/color_field.rb +1 -2
  35. data/lib/action_view/helpers/tags/date_field.rb +0 -1
  36. data/lib/action_view/helpers/tags/date_select.rb +0 -1
  37. data/lib/action_view/helpers/tags/datetime_field.rb +0 -1
  38. data/lib/action_view/helpers/tags/datetime_local_field.rb +0 -1
  39. data/lib/action_view/helpers/tags/label.rb +0 -1
  40. data/lib/action_view/helpers/tags/month_field.rb +0 -1
  41. data/lib/action_view/helpers/tags/radio_button.rb +0 -1
  42. data/lib/action_view/helpers/tags/select.rb +0 -1
  43. data/lib/action_view/helpers/tags/text_field.rb +0 -1
  44. data/lib/action_view/helpers/tags/time_field.rb +0 -1
  45. data/lib/action_view/helpers/tags/translator.rb +1 -6
  46. data/lib/action_view/helpers/tags/week_field.rb +0 -1
  47. data/lib/action_view/helpers/text_helper.rb +3 -4
  48. data/lib/action_view/helpers/translation_helper.rb +19 -17
  49. data/lib/action_view/helpers/url_helper.rb +14 -14
  50. data/lib/action_view/helpers.rb +0 -2
  51. data/lib/action_view/layouts.rb +5 -8
  52. data/lib/action_view/log_subscriber.rb +6 -7
  53. data/lib/action_view/lookup_context.rb +75 -32
  54. data/lib/action_view/path_set.rb +5 -11
  55. data/lib/action_view/railtie.rb +24 -1
  56. data/lib/action_view/record_identifier.rb +2 -3
  57. data/lib/action_view/renderer/abstract_renderer.rb +56 -4
  58. data/lib/action_view/renderer/partial_renderer/collection_caching.rb +63 -17
  59. data/lib/action_view/renderer/partial_renderer.rb +67 -57
  60. data/lib/action_view/renderer/renderer.rb +16 -4
  61. data/lib/action_view/renderer/streaming_template_renderer.rb +5 -7
  62. data/lib/action_view/renderer/template_renderer.rb +25 -20
  63. data/lib/action_view/rendering.rb +51 -32
  64. data/lib/action_view/routing_url_for.rb +12 -11
  65. data/lib/action_view/template/error.rb +30 -15
  66. data/lib/action_view/template/handlers/builder.rb +2 -2
  67. data/lib/action_view/template/handlers/erb/erubi.rb +7 -3
  68. data/lib/action_view/template/handlers/erb.rb +17 -8
  69. data/lib/action_view/template/handlers/html.rb +1 -1
  70. data/lib/action_view/template/handlers/raw.rb +2 -2
  71. data/lib/action_view/template/handlers.rb +27 -1
  72. data/lib/action_view/template/html.rb +14 -5
  73. data/lib/action_view/template/inline.rb +22 -0
  74. data/lib/action_view/template/raw_file.rb +28 -0
  75. data/lib/action_view/template/resolver.rb +134 -135
  76. data/lib/action_view/template/sources/file.rb +17 -0
  77. data/lib/action_view/template/sources.rb +13 -0
  78. data/lib/action_view/template/text.rb +5 -3
  79. data/lib/action_view/template.rb +102 -71
  80. data/lib/action_view/test_case.rb +3 -4
  81. data/lib/action_view/testing/resolvers.rb +33 -21
  82. data/lib/action_view/unbound_template.rb +31 -0
  83. data/lib/action_view/view_paths.rb +25 -2
  84. data/lib/action_view.rb +4 -2
  85. data/lib/assets/compiled/rails-ujs.js +30 -4
  86. metadata +27 -18
  87. data/lib/action_view/helpers/record_tag_helper.rb +0 -23
@@ -3,6 +3,7 @@
3
3
  require "active_support/core_ext/module/attr_internal"
4
4
  require "active_support/core_ext/module/attribute_accessors"
5
5
  require "active_support/ordered_options"
6
+ require "active_support/deprecation"
6
7
  require "action_view/log_subscriber"
7
8
  require "action_view/helpers"
8
9
  require "action_view/context"
@@ -151,7 +152,7 @@ module ActionView #:nodoc:
151
152
  # Specify whether rendering within namespaced controllers should prefix
152
153
  # the partial paths for ActiveModel objects with the namespace.
153
154
  # (e.g., an Admin::PostsController would render @post using /admin/posts/_post.erb)
154
- cattr_accessor :prefix_partial_path_with_controller_namespace, default: true
155
+ class_attribute :prefix_partial_path_with_controller_namespace, default: true
155
156
 
156
157
  # Specify default_formats that can be rendered.
157
158
  cattr_accessor :default_formats
@@ -179,37 +180,133 @@ module ActionView #:nodoc:
179
180
  def xss_safe? #:nodoc:
180
181
  true
181
182
  end
183
+
184
+ def with_empty_template_cache # :nodoc:
185
+ subclass = Class.new(self) {
186
+ # We can't implement these as self.class because subclasses will
187
+ # share the same template cache as superclasses, so "changed?" won't work
188
+ # correctly.
189
+ define_method(:compiled_method_container) { subclass }
190
+ define_singleton_method(:compiled_method_container) { subclass }
191
+ }
192
+ end
193
+
194
+ def changed?(other) # :nodoc:
195
+ compiled_method_container != other.compiled_method_container
196
+ end
182
197
  end
183
198
 
184
- attr_accessor :view_renderer
199
+ attr_reader :view_renderer, :lookup_context
185
200
  attr_internal :config, :assigns
186
201
 
187
- delegate :lookup_context, to: :view_renderer
188
202
  delegate :formats, :formats=, :locale, :locale=, :view_paths, :view_paths=, to: :lookup_context
189
203
 
190
204
  def assign(new_assigns) # :nodoc:
191
205
  @_assigns = new_assigns.each { |key, value| instance_variable_set("@#{key}", value) }
192
206
  end
193
207
 
194
- def initialize(context = nil, assigns = {}, controller = nil, formats = nil) #:nodoc:
208
+ # :stopdoc:
209
+
210
+ def self.build_lookup_context(context)
211
+ case context
212
+ when ActionView::Renderer
213
+ context.lookup_context
214
+ when Array
215
+ ActionView::LookupContext.new(context)
216
+ when ActionView::PathSet
217
+ ActionView::LookupContext.new(context)
218
+ when nil
219
+ ActionView::LookupContext.new([])
220
+ else
221
+ raise NotImplementedError, context.class.name
222
+ end
223
+ end
224
+
225
+ def self.empty
226
+ with_view_paths([])
227
+ end
228
+
229
+ def self.with_view_paths(view_paths, assigns = {}, controller = nil)
230
+ with_context ActionView::LookupContext.new(view_paths), assigns, controller
231
+ end
232
+
233
+ def self.with_context(context, assigns = {}, controller = nil)
234
+ new context, assigns, controller
235
+ end
236
+
237
+ NULL = Object.new
238
+
239
+ # :startdoc:
240
+
241
+ def initialize(lookup_context = nil, assigns = {}, controller = nil, formats = NULL) #:nodoc:
195
242
  @_config = ActiveSupport::InheritableOptions.new
196
243
 
197
- if context.is_a?(ActionView::Renderer)
198
- @view_renderer = context
244
+ unless formats == NULL
245
+ ActiveSupport::Deprecation.warn <<~eowarn.squish
246
+ Passing formats to ActionView::Base.new is deprecated
247
+ eowarn
248
+ end
249
+
250
+ case lookup_context
251
+ when ActionView::LookupContext
252
+ @lookup_context = lookup_context
199
253
  else
200
- lookup_context = context.is_a?(ActionView::LookupContext) ?
201
- context : ActionView::LookupContext.new(context)
202
- lookup_context.formats = formats if formats
203
- lookup_context.prefixes = controller._prefixes if controller
204
- @view_renderer = ActionView::Renderer.new(lookup_context)
254
+ ActiveSupport::Deprecation.warn <<~eowarn.squish
255
+ ActionView::Base instances should be constructed with a lookup context,
256
+ assignments, and a controller.
257
+ eowarn
258
+ @lookup_context = self.class.build_lookup_context(lookup_context)
205
259
  end
206
260
 
261
+ @view_renderer = ActionView::Renderer.new @lookup_context
262
+ @current_template = nil
263
+
207
264
  @cache_hit = {}
208
265
  assign(assigns)
209
266
  assign_controller(controller)
210
267
  _prepare_context
211
268
  end
212
269
 
270
+ def _run(method, template, locals, buffer, &block)
271
+ _old_output_buffer, _old_virtual_path, _old_template = @output_buffer, @virtual_path, @current_template
272
+ @current_template = template
273
+ @output_buffer = buffer
274
+ send(method, locals, buffer, &block)
275
+ ensure
276
+ @output_buffer, @virtual_path, @current_template = _old_output_buffer, _old_virtual_path, _old_template
277
+ end
278
+
279
+ def compiled_method_container
280
+ if self.class == ActionView::Base
281
+ ActiveSupport::Deprecation.warn <<~eowarn.squish
282
+ ActionView::Base instances must implement `compiled_method_container`
283
+ or use the class method `with_empty_template_cache` for constructing
284
+ an ActionView::Base instance that has an empty cache.
285
+ eowarn
286
+ end
287
+
288
+ self.class
289
+ end
290
+
291
+ def in_rendering_context(options)
292
+ old_view_renderer = @view_renderer
293
+ old_lookup_context = @lookup_context
294
+
295
+ if !lookup_context.html_fallback_for_js && options[:formats]
296
+ formats = Array(options[:formats])
297
+ if formats == [:js]
298
+ formats << :html
299
+ end
300
+ @lookup_context = lookup_context.with_prepended_formats(formats)
301
+ @view_renderer = ActionView::Renderer.new @lookup_context
302
+ end
303
+
304
+ yield @view_renderer
305
+ ensure
306
+ @view_renderer = old_view_renderer
307
+ @lookup_context = old_lookup_context
308
+ end
309
+
213
310
  ActiveSupport.run_load_hooks(:action_view, self)
214
311
  end
215
312
  end
@@ -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,53 @@
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
+ def dirs_to_watch
45
+ fs_paths = all_view_paths.grep(FileSystemResolver)
46
+ fs_paths.map(&:path).sort.uniq
47
+ end
48
+
49
+ def all_view_paths
50
+ ActionView::ViewPaths.all_view_paths.flat_map(&:paths)
51
+ end
52
+ end
53
+ end
@@ -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 ActionController, a Context must just include this module.
14
- # The initialization of the variables used by the context (@output_buffer, @view_flow,
15
- # and @virtual_path) is responsibility of the object that includes this module
16
- # (although you can call _prepare_context defined below).
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.
@@ -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> - Template name
21
- # * <tt>finder</tt> - An instance of <tt>ActionView::LookupContext</tt>
22
- # * <tt>dependencies</tt> - An array of dependent views
23
- def digest(name:, finder:, dependencies: [])
24
- dependencies ||= []
25
- cache_key = [ name, finder.rendered_format, dependencies ].flatten.compact.join(".")
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
- format = finder.rendered_format
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
@@ -68,7 +68,6 @@ module ActionView
68
68
  end
69
69
 
70
70
  private
71
-
72
71
  def inside_fiber?
73
72
  Fiber.current.object_id != @root
74
73
  end
@@ -7,9 +7,9 @@ module ActionView
7
7
  end
8
8
 
9
9
  module VERSION
10
- MAJOR = 5
11
- MINOR = 2
12
- TINY = 8
10
+ MAJOR = 6
11
+ MINOR = 0
12
+ TINY = 6
13
13
  PRE = "1"
14
14
 
15
15
  STRING = [MAJOR, MINOR, TINY, PRE].compact.join(".")
@@ -38,7 +38,6 @@ module ActionView
38
38
  end
39
39
 
40
40
  private
41
-
42
41
  def object_has_errors?
43
42
  object.respond_to?(:errors) && object.errors.respond_to?(:[]) && error_message.present?
44
43
  end
@@ -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<tt> - When set to true, adds an automatic nonce value if
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".freeze, "", tag_options)
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
@@ -274,7 +274,7 @@ module ActionView
274
274
  crossorigin = "anonymous" if crossorigin == true || (crossorigin.blank? && as_type == "font")
275
275
  nopush = options.delete(:nopush) || false
276
276
 
277
- link_tag = tag.link({
277
+ link_tag = tag.link(**{
278
278
  rel: "preload",
279
279
  href: href,
280
280
  as: as_type,
@@ -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(resize: "100x100"))
337
- # # => <img src="/rails/active_storage/variants/.../tiger.jpg" />
338
- # image_tag(user.avatar.variant(resize: "100x100"), size: '100')
339
- # # => <img width="100" height="100" src="/rails/active_storage/variants/.../tiger.jpg" />
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 via a Rake task. Make sure to use a +Proc+ instead of a lambda,
102
- # since a +Proc+ allows missing parameters and sets them to +nil+.
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(/([\?#].+)$/, "".freeze)
191
+ tail, source = source[/([\?#].+)$/], source.sub(/([\?#].+)$/, "")
191
192
 
192
193
  if extname = compute_asset_extname(source, options)
193
194
  source = "#{source}#{extname}"
@@ -166,7 +166,7 @@ module ActionView
166
166
  def cache(name = {}, options = {}, &block)
167
167
  if controller.respond_to?(:perform_caching) && controller.perform_caching
168
168
  name_options = options.slice(:skip_digest, :virtual_path)
169
- safe_concat(fragment_for(cache_fragment_name(name, name_options), options, &block))
169
+ safe_concat(fragment_for(cache_fragment_name(name, **name_options), options, &block))
170
170
  else
171
171
  yield
172
172
  end
@@ -201,34 +201,41 @@ 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 +skip_digest:+ true to cache, the digestion of cache
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
216
  end
217
217
  end
218
218
 
219
- private
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)
220
221
 
221
- def fragment_name_with_digest(name, virtual_path)
222
+ if digest.present?
223
+ "#{template.virtual_path}:#{digest}"
224
+ else
225
+ template.virtual_path
226
+ end
227
+ end
228
+
229
+ private
230
+ def fragment_name_with_digest(name, virtual_path, digest_path)
222
231
  virtual_path ||= @virtual_path
223
232
 
224
- if virtual_path
233
+ if virtual_path || digest_path
225
234
  name = controller.url_for(name).split("://").last if name.is_a?(Hash)
226
235
 
227
- if digest = Digestor.digest(name: virtual_path, finder: lookup_context, dependencies: view_cache_dependencies).presence
228
- [ "#{virtual_path}:#{digest}", name ]
229
- else
230
- [ virtual_path, name ]
231
- end
236
+ digest_path ||= digest_path_from_template(@current_template)
237
+
238
+ [ digest_path, name ]
232
239
  else
233
240
  name
234
241
  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
- tag("meta", name: "csp-nonce", content: content_security_policy_nonce)
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)