actionview 4.2.11.1 → 6.1.5

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 (117) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +232 -186
  3. data/MIT-LICENSE +1 -2
  4. data/README.rdoc +9 -8
  5. data/lib/action_view/base.rb +115 -39
  6. data/lib/action_view/buffers.rb +18 -1
  7. data/lib/action_view/cache_expiry.rb +52 -0
  8. data/lib/action_view/context.rb +8 -12
  9. data/lib/action_view/dependency_tracker.rb +61 -21
  10. data/lib/action_view/digestor.rb +89 -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 +282 -83
  15. data/lib/action_view/helpers/asset_url_helper.rb +175 -69
  16. data/lib/action_view/helpers/atom_feed_helper.rb +20 -17
  17. data/lib/action_view/helpers/cache_helper.rb +107 -43
  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 +232 -130
  23. data/lib/action_view/helpers/debug_helper.rb +7 -6
  24. data/lib/action_view/helpers/form_helper.rb +808 -146
  25. data/lib/action_view/helpers/form_options_helper.rb +124 -78
  26. data/lib/action_view/helpers/form_tag_helper.rb +120 -74
  27. data/lib/action_view/helpers/javascript_helper.rb +33 -17
  28. data/lib/action_view/helpers/number_helper.rb +87 -62
  29. data/lib/action_view/helpers/output_safety_helper.rb +36 -4
  30. data/lib/action_view/helpers/rendering_helper.rb +21 -10
  31. data/lib/action_view/helpers/sanitize_helper.rb +30 -31
  32. data/lib/action_view/helpers/tag_helper.rb +269 -68
  33. data/lib/action_view/helpers/tags/base.rb +141 -97
  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 +3 -2
  42. data/lib/action_view/helpers/tags/date_select.rb +38 -37
  43. data/lib/action_view/helpers/tags/datetime_field.rb +4 -3
  44. data/lib/action_view/helpers/tags/datetime_local_field.rb +3 -2
  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 +6 -0
  50. data/lib/action_view/helpers/tags/label.rb +7 -2
  51. data/lib/action_view/helpers/tags/month_field.rb +3 -2
  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 +3 -2
  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 +3 -2
  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 +150 -68
  71. data/lib/action_view/helpers/url_helper.rb +284 -117
  72. data/lib/action_view/helpers.rb +5 -3
  73. data/lib/action_view/layouts.rb +68 -63
  74. data/lib/action_view/log_subscriber.rb +77 -10
  75. data/lib/action_view/lookup_context.rb +134 -91
  76. data/lib/action_view/model_naming.rb +3 -1
  77. data/lib/action_view/path_set.rb +26 -24
  78. data/lib/action_view/railtie.rb +62 -13
  79. data/lib/action_view/record_identifier.rb +53 -26
  80. data/lib/action_view/renderer/abstract_renderer.rb +151 -14
  81. data/lib/action_view/renderer/collection_renderer.rb +196 -0
  82. data/lib/action_view/renderer/object_renderer.rb +34 -0
  83. data/lib/action_view/renderer/partial_renderer/collection_caching.rb +102 -0
  84. data/lib/action_view/renderer/partial_renderer.rb +55 -303
  85. data/lib/action_view/renderer/renderer.rb +66 -9
  86. data/lib/action_view/renderer/streaming_template_renderer.rb +58 -54
  87. data/lib/action_view/renderer/template_renderer.rb +82 -73
  88. data/lib/action_view/rendering.rb +71 -45
  89. data/lib/action_view/routing_url_for.rb +34 -23
  90. data/lib/action_view/tasks/cache_digests.rake +25 -0
  91. data/lib/action_view/template/error.rb +44 -29
  92. data/lib/action_view/template/handlers/builder.rb +12 -13
  93. data/lib/action_view/template/handlers/erb/erubi.rb +89 -0
  94. data/lib/action_view/template/handlers/erb.rb +23 -89
  95. data/lib/action_view/template/handlers/html.rb +11 -0
  96. data/lib/action_view/template/handlers/raw.rb +4 -4
  97. data/lib/action_view/template/handlers.rb +12 -8
  98. data/lib/action_view/template/html.rb +10 -11
  99. data/lib/action_view/template/inline.rb +22 -0
  100. data/lib/action_view/template/raw_file.rb +25 -0
  101. data/lib/action_view/template/renderable.rb +24 -0
  102. data/lib/action_view/template/resolver.rb +263 -197
  103. data/lib/action_view/template/sources/file.rb +17 -0
  104. data/lib/action_view/template/sources.rb +13 -0
  105. data/lib/action_view/template/text.rb +8 -10
  106. data/lib/action_view/template/types.rb +18 -18
  107. data/lib/action_view/template.rb +108 -92
  108. data/lib/action_view/test_case.rb +66 -53
  109. data/lib/action_view/testing/resolvers.rb +24 -33
  110. data/lib/action_view/unbound_template.rb +31 -0
  111. data/lib/action_view/version.rb +3 -1
  112. data/lib/action_view/view_paths.rb +73 -58
  113. data/lib/action_view.rb +14 -8
  114. data/lib/assets/compiled/rails-ujs.js +746 -0
  115. metadata +42 -29
  116. data/lib/action_view/helpers/record_tag_helper.rb +0 -108
  117. data/lib/action_view/tasks/dependencies.rake +0 -23
@@ -1,123 +1,127 @@
1
- require 'thread_safe'
2
- require 'action_view/dependency_tracker'
3
- require 'monitor'
1
+ # frozen_string_literal: true
2
+
3
+ require "action_view/dependency_tracker"
4
4
 
5
5
  module ActionView
6
6
  class Digestor
7
- cattr_reader(:cache)
8
- @@cache = ThreadSafe::Cache.new
9
- @@digest_monitor = Monitor.new
7
+ @@digest_mutex = Mutex.new
10
8
 
11
9
  class << self
12
10
  # Supported options:
13
11
  #
14
- # * <tt>name</tt> - Template name
15
- # * <tt>finder</tt> - An instance of ActionView::LookupContext
16
- # * <tt>dependencies</tt> - An array of dependent views
17
- # * <tt>partial</tt> - Specifies whether the template is a partial
18
- def digest(options)
19
- options.assert_valid_keys(:name, :finder, :dependencies, :partial)
20
-
21
- cache_key = ([ options[:name], options[:finder].details_key.hash ].compact + Array.wrap(options[:dependencies])).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
22
22
 
23
23
  # this is a correctly done double-checked locking idiom
24
- # (ThreadSafe::Cache's lookups have volatile semantics)
25
- @@cache[cache_key] || @@digest_monitor.synchronize do
26
- @@cache.fetch(cache_key) do # re-check under lock
27
- compute_and_store_digest(cache_key, options)
24
+ # (Concurrent::Map's lookups have volatile semantics)
25
+ finder.digest_cache[cache_key] || @@digest_mutex.synchronize do
26
+ finder.digest_cache.fetch(cache_key) do # re-check under lock
27
+ partial = name.include?("/_")
28
+ root = tree(name, finder, partial)
29
+ dependencies.each do |injected_dep|
30
+ root.children << Injected.new(injected_dep, nil, nil)
31
+ end if dependencies
32
+ finder.digest_cache[cache_key] = root.digest(finder)
28
33
  end
29
34
  end
30
35
  end
31
36
 
32
- private
33
- def compute_and_store_digest(cache_key, options) # called under @@digest_monitor lock
34
- klass = if options[:partial] || options[:name].include?("/_")
35
- # Prevent re-entry or else recursive templates will blow the stack.
36
- # There is no need to worry about other threads seeing the +false+ value,
37
- # as they will then have to wait for this thread to let go of the @@digest_monitor lock.
38
- pre_stored = @@cache.put_if_absent(cache_key, false).nil? # put_if_absent returns nil on insertion
39
- PartialDigestor
40
- else
41
- Digestor
42
- end
37
+ def logger
38
+ ActionView::Base.logger || NullLogger
39
+ end
43
40
 
44
- digest = klass.new(options).digest
45
- # Store the actual digest if config.cache_template_loading is true
46
- @@cache[cache_key] = stored_digest = digest if ActionView::Resolver.caching?
47
- digest
48
- ensure
49
- # something went wrong or ActionView::Resolver.caching? is false, make sure not to corrupt the @@cache
50
- @@cache.delete_pair(cache_key, false) if pre_stored && !stored_digest
51
- end
52
- end
41
+ # Create a dependency tree for template named +name+.
42
+ def tree(name, finder, partial = false, seen = {})
43
+ logical_name = name.gsub(%r|/_|, "/")
44
+ interpolated = name.include?("#")
53
45
 
54
- attr_reader :name, :finder, :options
46
+ if !interpolated && (template = find_template(finder, logical_name, [], partial, []))
47
+ if node = seen[template.identifier] # handle cycles in the tree
48
+ node
49
+ else
50
+ node = seen[template.identifier] = Node.create(name, logical_name, template, partial)
55
51
 
56
- def initialize(options)
57
- @name, @finder = options.values_at(:name, :finder)
58
- @options = options.except(:name, :finder)
59
- end
52
+ deps = DependencyTracker.find_dependencies(name, template, finder.view_paths)
53
+ deps.uniq { |n| n.gsub(%r|/_|, "/") }.each do |dep_file|
54
+ node.children << tree(dep_file, finder, true, seen)
55
+ end
56
+ node
57
+ end
58
+ else
59
+ unless interpolated # Dynamic template partial names can never be tracked
60
+ logger.error " Couldn't find template for digesting: #{name}"
61
+ end
60
62
 
61
- def digest
62
- Digest::MD5.hexdigest("#{source}-#{dependency_digest}").tap do |digest|
63
- logger.try :debug, " Cache digest for #{template.inspect}: #{digest}"
63
+ seen[name] ||= Missing.new(name, logical_name, nil)
64
+ end
64
65
  end
65
- rescue ActionView::MissingTemplate
66
- logger.try :error, " Couldn't find template for digesting: #{name}"
67
- ''
68
- end
69
66
 
70
- def dependencies
71
- DependencyTracker.find_dependencies(name, template)
72
- rescue ActionView::MissingTemplate
73
- logger.try :error, " '#{name}' file doesn't exist, so no dependencies"
74
- []
67
+ private
68
+ def find_template(finder, name, prefixes, partial, keys)
69
+ finder.disable_cache do
70
+ finder.find_all(name, prefixes, partial, keys).first
71
+ end
72
+ end
75
73
  end
76
74
 
77
- def nested_dependencies
78
- dependencies.collect do |dependency|
79
- dependencies = PartialDigestor.new(name: dependency, finder: finder).nested_dependencies
80
- dependencies.any? ? { dependency => dependencies } : dependency
81
- end
82
- end
75
+ class Node
76
+ attr_reader :name, :logical_name, :template, :children
83
77
 
84
- private
85
- def logger
86
- ActionView::Base.logger
78
+ def self.create(name, logical_name, template, partial)
79
+ klass = partial ? Partial : Node
80
+ klass.new(name, logical_name, template, [])
87
81
  end
88
82
 
89
- def logical_name
90
- name.gsub(%r|/_|, "/")
83
+ def initialize(name, logical_name, template, children = [])
84
+ @name = name
85
+ @logical_name = logical_name
86
+ @template = template
87
+ @children = children
91
88
  end
92
89
 
93
- def partial?
94
- false
90
+ def digest(finder, stack = [])
91
+ ActiveSupport::Digest.hexdigest("#{template.source}-#{dependency_digest(finder, stack)}")
95
92
  end
96
93
 
97
- def template
98
- @template ||= finder.disable_cache { finder.find(logical_name, [], partial?) }
94
+ def dependency_digest(finder, stack)
95
+ children.map do |node|
96
+ if stack.include?(node)
97
+ false
98
+ else
99
+ finder.digest_cache[node.name] ||= begin
100
+ stack.push node
101
+ node.digest(finder, stack).tap { stack.pop }
102
+ end
103
+ end
104
+ end.join("-")
99
105
  end
100
106
 
101
- def source
102
- template.source
107
+ def to_dep_map
108
+ children.any? ? { name => children.map(&:to_dep_map) } : name
103
109
  end
110
+ end
104
111
 
105
- def dependency_digest
106
- template_digests = dependencies.collect do |template_name|
107
- Digestor.digest(name: template_name, finder: finder, partial: true)
108
- end
112
+ class Partial < Node; end
109
113
 
110
- (template_digests + injected_dependencies).join("-")
111
- end
114
+ class Missing < Node
115
+ def digest(finder, _ = []) "" end
116
+ end
112
117
 
113
- def injected_dependencies
114
- Array.wrap(options[:dependencies])
115
- end
116
- end
118
+ class Injected < Node
119
+ def digest(finder, _ = []) name end
120
+ end
117
121
 
118
- class PartialDigestor < Digestor # :nodoc:
119
- def partial?
120
- true
122
+ class NullLogger
123
+ def self.debug(_); end
124
+ def self.error(_); end
121
125
  end
122
126
  end
123
127
  end
@@ -1,11 +1,13 @@
1
- require 'active_support/core_ext/string/output_safety'
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/core_ext/string/output_safety"
2
4
 
3
5
  module ActionView
4
6
  class OutputFlow #:nodoc:
5
7
  attr_reader :content
6
8
 
7
9
  def initialize
8
- @content = Hash.new { |h,k| h[k] = ActiveSupport::SafeBuffer.new }
10
+ @content = Hash.new { |h, k| h[k] = ActiveSupport::SafeBuffer.new }
9
11
  end
10
12
 
11
13
  # Called by _layout_for to read stored values.
@@ -23,7 +25,6 @@ module ActionView
23
25
  @content[key] << value
24
26
  end
25
27
  alias_method :append!, :append
26
-
27
28
  end
28
29
 
29
30
  class StreamingFlow < OutputFlow #:nodoc:
@@ -37,9 +38,8 @@ module ActionView
37
38
  end
38
39
 
39
40
  # Try to get stored content. If the content
40
- # is not available and we are inside the layout
41
- # fiber, we set that we are waiting for the given
42
- # key and yield.
41
+ # is not available and we're inside the layout fiber,
42
+ # then it will begin waiting for the given key and yield.
43
43
  def get(key)
44
44
  return super if @content.key?(key)
45
45
 
@@ -60,17 +60,16 @@ module ActionView
60
60
  end
61
61
 
62
62
  # Appends the contents for the given key. This is called
63
- # by provides and resumes back to the fiber if it is
64
- # the key it is waiting for.
63
+ # by providing and resuming back to the fiber,
64
+ # if that's the key it's waiting for.
65
65
  def append!(key, value)
66
66
  super
67
67
  @fiber.resume if @waiting_for == key
68
68
  end
69
69
 
70
70
  private
71
-
72
- def inside_fiber?
73
- Fiber.current.object_id != @root
74
- end
71
+ def inside_fiber?
72
+ Fiber.current.object_id != @root
73
+ end
75
74
  end
76
75
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActionView
2
4
  # Returns the version of the currently loaded Action View as a <tt>Gem::Version</tt>
3
5
  def self.gem_version
@@ -5,10 +7,10 @@ module ActionView
5
7
  end
6
8
 
7
9
  module VERSION
8
- MAJOR = 4
9
- MINOR = 2
10
- TINY = 11
11
- PRE = "1"
10
+ MAJOR = 6
11
+ MINOR = 1
12
+ TINY = 5
13
+ PRE = nil
12
14
 
13
15
  STRING = [MAJOR, MINOR, TINY, PRE].compact.join(".")
14
16
  end
@@ -1,9 +1,11 @@
1
- require 'active_support/core_ext/module/attribute_accessors'
2
- require 'active_support/core_ext/enumerable'
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/core_ext/module/attribute_accessors"
4
+ require "active_support/core_ext/enumerable"
3
5
 
4
6
  module ActionView
5
7
  # = Active Model Helpers
6
- module Helpers
8
+ module Helpers #:nodoc:
7
9
  module ActiveModelHelper
8
10
  end
9
11
 
@@ -15,8 +17,8 @@ module ActionView
15
17
  end
16
18
  end
17
19
 
18
- def content_tag(*)
19
- error_wrapping(super)
20
+ def content_tag(type, options, *)
21
+ select_markup_helper?(type) ? super : error_wrapping(super)
20
22
  end
21
23
 
22
24
  def tag(type, options, *)
@@ -36,14 +38,17 @@ module ActionView
36
38
  end
37
39
 
38
40
  private
41
+ def object_has_errors?
42
+ object.respond_to?(:errors) && object.errors.respond_to?(:[]) && error_message.present?
43
+ end
39
44
 
40
- def object_has_errors?
41
- object.respond_to?(:errors) && object.errors.respond_to?(:[]) && error_message.present?
42
- end
45
+ def select_markup_helper?(type)
46
+ ["optgroup", "option"].include?(type)
47
+ end
43
48
 
44
- def tag_generate_errors?(options)
45
- options['type'] != 'hidden'
46
- end
49
+ def tag_generate_errors?(options)
50
+ options["type"] != "hidden"
51
+ end
47
52
  end
48
53
  end
49
54
  end