actionview 6.0.0.beta3 → 6.0.0.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.

Files changed (34) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +40 -4
  3. data/README.rdoc +3 -1
  4. data/lib/action_view.rb +2 -1
  5. data/lib/action_view/base.rb +4 -4
  6. data/lib/action_view/cache_expiry.rb +49 -0
  7. data/lib/action_view/digestor.rb +0 -6
  8. data/lib/action_view/gem_version.rb +1 -1
  9. data/lib/action_view/helpers/form_helper.rb +2 -2
  10. data/lib/action_view/helpers/form_tag_helper.rb +1 -1
  11. data/lib/action_view/helpers/output_safety_helper.rb +1 -1
  12. data/lib/action_view/helpers/tags/base.rb +1 -1
  13. data/lib/action_view/helpers/translation_helper.rb +2 -2
  14. data/lib/action_view/helpers/url_helper.rb +1 -1
  15. data/lib/action_view/lookup_context.rb +11 -4
  16. data/lib/action_view/path_set.rb +5 -10
  17. data/lib/action_view/railtie.rb +1 -1
  18. data/lib/action_view/renderer/partial_renderer/collection_caching.rb +20 -13
  19. data/lib/action_view/renderer/streaming_template_renderer.rb +1 -1
  20. data/lib/action_view/renderer/template_renderer.rb +9 -3
  21. data/lib/action_view/rendering.rb +3 -2
  22. data/lib/action_view/template.rb +43 -50
  23. data/lib/action_view/template/error.rb +21 -1
  24. data/lib/action_view/template/handlers.rb +3 -3
  25. data/lib/action_view/template/handlers/erb/erubi.rb +2 -2
  26. data/lib/action_view/template/raw_file.rb +28 -0
  27. data/lib/action_view/template/resolver.rb +73 -117
  28. data/lib/action_view/template/sources.rb +13 -0
  29. data/lib/action_view/template/sources/file.rb +17 -0
  30. data/lib/action_view/testing/resolvers.rb +9 -10
  31. data/lib/action_view/unbound_template.rb +32 -0
  32. data/lib/assets/compiled/rails-ujs.js +14 -8
  33. metadata +16 -12
  34. data/lib/action_view/file_template.rb +0 -33
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 4233564ef5c23bc9a517b08297234c7b0a79e061fb666f88c908fb182e186716
4
- data.tar.gz: 170f5a8f9fc725f26c483f7b5b7e900d2888ef7090ffa6d9c75940ffcc30af34
3
+ metadata.gz: d46b0e667c524b53bbcfd7291119c3078c1bcef2f379077610f11efa75cb7bcd
4
+ data.tar.gz: 3952ce8b418d28245b3ba4a0126435958facc728363abd50deb0e6b110556b65
5
5
  SHA512:
6
- metadata.gz: a3abde252c689dbea7c168cd8f298ac63d5f6798ea64f7619260e10214b3df21a3feab194449de53d51e4e951d4bd747236f69536554f3dfd81b6738f52d15ae
7
- data.tar.gz: 6d409d208552a764dc899bef3c3794f711ae9cea39ce2546630b1f6aed32e0685e00434683392ae7cdcc5b0a01bc5c812bb64b4e69ef267054050b586e6c6d46
6
+ metadata.gz: dfc23eddf6eeb31093fa017f53ebc46c5a115d1d0edbc3ab40747eb243d4516e99c74d5c6d497bcb9731a62ab224ecde5f62352b50f57ab384a9595ac6d2ae53
7
+ data.tar.gz: d8abfa6ea6c991820b67fb389c629f6b49d09610c1d0821e009084e475649b6aef7a861c620960ef58b9efa0d4a0709b9606690f6b19557910c0fd3946130f5f
@@ -1,22 +1,58 @@
1
+ ## Rails 6.0.0.rc1 (April 24, 2019) ##
2
+
3
+ * Fix partial caching skips same item issue
4
+
5
+ If we render cached collection partials with repeated items, those repeated items
6
+ will get skipped. For example, if you have 5 identical items in your collection, Rails
7
+ only renders the first one when `cached` is set to true. But it should render all
8
+ 5 items instead.
9
+
10
+ Fixes #35114.
11
+
12
+ *Stan Lo*
13
+
14
+ * Only clear ActionView cache in development on file changes
15
+
16
+ To speed up development mode, view caches are only cleared when files in
17
+ the view paths have changed. Applications which have implemented custom
18
+ `ActionView::Resolver` subclasses may need to add their own cache clearing.
19
+
20
+ *John Hawthorn*
21
+
22
+ * Fix `ActionView::FixtureResolver` so that it handles template variants correctly.
23
+
24
+ *Edward Rudd*
25
+
26
+
1
27
  ## Rails 6.0.0.beta3 (March 11, 2019) ##
2
28
 
3
- * No changes.
29
+ * Only accept formats from registered mime types
30
+
31
+ A lack of filtering on mime types could allow an attacker to read
32
+ arbitrary files on the target server or to perform a denial of service
33
+ attack.
34
+
35
+ Fixes CVE-2019-5418
36
+ Fixes CVE-2019-5419
37
+
38
+ *John Hawthorn*, *Eileen M. Uchitelle*, *Aaron Patterson*
4
39
 
5
40
 
6
41
  ## Rails 6.0.0.beta2 (February 25, 2019) ##
7
42
 
8
- * ActionView::Template.finalize_compiled_template_methods is deprecated with
43
+ * `ActionView::Template.finalize_compiled_template_methods` is deprecated with
9
44
  no replacement.
10
45
 
11
46
  *tenderlove*
12
47
 
13
- * config.action_view.finalize_compiled_template_methods is deprecated with
48
+ * `config.action_view.finalize_compiled_template_methods` is deprecated with
14
49
  no replacement.
15
50
 
16
51
  *tenderlove*
17
52
 
18
53
  * Ensure unique DOM IDs for collection inputs with float values.
19
- Fixes #34974
54
+
55
+ Fixes #34974.
20
56
 
21
57
  *Mark Edmondson*
22
58
 
@@ -5,6 +5,8 @@ view helpers that assist when building HTML forms, Atom feeds and more.
5
5
  Template formats that Action View handles are ERB (embedded Ruby, typically
6
6
  used to inline short Ruby snippets inside HTML), and XML Builder.
7
7
 
8
+ You can read more about Action View in the {Action View Overview}[https://edgeguides.rubyonrails.org/action_view_overview.html] guide.
9
+
8
10
  == Download and installation
9
11
 
10
12
  The latest version of Action View can be installed with RubyGems:
@@ -27,7 +29,7 @@ Action View is released under the MIT license:
27
29
 
28
30
  API documentation is at
29
31
 
30
- * http://api.rubyonrails.org
32
+ * https://api.rubyonrails.org
31
33
 
32
34
  Bug reports for the Ruby on Rails project can be filed here:
33
35
 
@@ -44,7 +44,7 @@ module ActionView
44
44
  autoload :Rendering
45
45
  autoload :RoutingUrlFor
46
46
  autoload :Template
47
- autoload :FileTemplate
47
+ autoload :UnboundTemplate
48
48
  autoload :ViewPaths
49
49
 
50
50
  autoload_under "renderer" do
@@ -81,6 +81,7 @@ module ActionView
81
81
  end
82
82
  end
83
83
 
84
+ autoload :CacheExpiry
84
85
  autoload :TestCase
85
86
 
86
87
  def self.eager_load!
@@ -242,7 +242,7 @@ module ActionView #:nodoc:
242
242
  @_config = ActiveSupport::InheritableOptions.new
243
243
 
244
244
  unless formats == NULL
245
- ActiveSupport::Deprecation.warn <<~eowarn
245
+ ActiveSupport::Deprecation.warn <<~eowarn.squish
246
246
  Passing formats to ActionView::Base.new is deprecated
247
247
  eowarn
248
248
  end
@@ -251,7 +251,7 @@ module ActionView #:nodoc:
251
251
  when ActionView::LookupContext
252
252
  @lookup_context = lookup_context
253
253
  else
254
- ActiveSupport::Deprecation.warn <<~eowarn
254
+ ActiveSupport::Deprecation.warn <<~eowarn.squish
255
255
  ActionView::Base instances should be constructed with a lookup context,
256
256
  assignments, and a controller.
257
257
  eowarn
@@ -267,7 +267,7 @@ module ActionView #:nodoc:
267
267
  _prepare_context
268
268
  end
269
269
 
270
- def run(method, template, locals, buffer, &block)
270
+ def _run(method, template, locals, buffer, &block)
271
271
  _old_output_buffer, _old_virtual_path, _old_template = @output_buffer, @virtual_path, @current_template
272
272
  @current_template = template
273
273
  @output_buffer = buffer
@@ -278,7 +278,7 @@ module ActionView #:nodoc:
278
278
 
279
279
  def compiled_method_container
280
280
  if self.class == ActionView::Base
281
- ActiveSupport::Deprecation.warn <<~eowarn
281
+ ActiveSupport::Deprecation.warn <<~eowarn.squish
282
282
  ActionView::Base instances must implement `compiled_method_container`
283
283
  or use the class method `with_empty_template_cache` for constructing
284
284
  an ActionView::Base instances that has an empty cache.
@@ -0,0 +1,49 @@
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
+ end
20
+
21
+ def clear_cache_if_necessary
22
+ watched_dirs = dirs_to_watch
23
+ if watched_dirs != @watched_dirs
24
+ @watched_dirs = watched_dirs
25
+ @watcher = @watcher_class.new([], watched_dirs) do
26
+ clear_cache
27
+ end
28
+ @watcher.execute
29
+ else
30
+ @watcher.execute_if_updated
31
+ end
32
+ end
33
+
34
+ def clear_cache
35
+ ActionView::LookupContext::DetailsKey.clear
36
+ end
37
+
38
+ private
39
+
40
+ def dirs_to_watch
41
+ fs_paths = all_view_paths.grep(FileSystemResolver)
42
+ fs_paths.map(&:path).sort.uniq
43
+ end
44
+
45
+ def all_view_paths
46
+ ActionView::ViewPaths.all_view_paths.flat_map(&:paths)
47
+ end
48
+ end
49
+ end
@@ -6,12 +6,6 @@ module ActionView
6
6
  class Digestor
7
7
  @@digest_mutex = Mutex.new
8
8
 
9
- module PerExecutionDigestCacheExpiry
10
- def self.before(target)
11
- ActionView::LookupContext::DetailsKey.clear
12
- end
13
- end
14
-
15
9
  class << self
16
10
  # Supported options:
17
11
  #
@@ -10,7 +10,7 @@ module ActionView
10
10
  MAJOR = 6
11
11
  MINOR = 0
12
12
  TINY = 0
13
- PRE = "beta3"
13
+ PRE = "rc1"
14
14
 
15
15
  STRING = [MAJOR, MINOR, TINY, PRE].compact.join(".")
16
16
  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, &Proc.new)
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)
@@ -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 url configured with <tt>url_for_options</tt> just like
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
@@ -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}[http://api.rubyonrails.org/classes/Array.html#method-i-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)
@@ -138,7 +138,7 @@ module ActionView
138
138
  end
139
139
 
140
140
  def sanitized_value(value)
141
- value.to_s.gsub(/[\s\.]/, "_").gsub(/[^-[[:word:]]]/, "").mb_chars.downcase.to_s
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)
@@ -114,7 +114,7 @@ module ActionView
114
114
 
115
115
  # Delegates to <tt>I18n.localize</tt> with no additional functionality.
116
116
  #
117
- # See http://rubydoc.info/github/svenfuchs/i18n/master/I18n/Backend/Base:localize
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
- /([_.]|\b)html\z/.match?(key.to_s)
141
+ /(?:_|\b)html\z/.match?(key.to_s)
142
142
  end
143
143
  end
144
144
  end
@@ -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 url doesn't have any either. This lets the function
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
@@ -130,9 +130,8 @@ module ActionView
130
130
  end
131
131
  alias :find_template :find
132
132
 
133
- def find_file(name, prefixes = [], partial = false, keys = [], options = {})
134
- @view_paths.find_file(*args_for_lookup(name, prefixes, partial, keys, options))
135
- end
133
+ alias :find_file :find
134
+ deprecate :find_file
136
135
 
137
136
  def find_all(name, prefixes = [], partial = false, keys = [], options = {})
138
137
  @view_paths.find_all(*args_for_lookup(name, prefixes, partial, keys, options))
@@ -154,7 +153,7 @@ module ActionView
154
153
  view_paths = build_view_paths((@view_paths.paths + self.class.fallbacks).uniq)
155
154
 
156
155
  if block_given?
157
- ActiveSupport::Deprecation.warn <<~eowarn
156
+ ActiveSupport::Deprecation.warn <<~eowarn.squish
158
157
  Calling `with_fallbacks` with a block is deprecated. Call methods on
159
158
  the lookup context returned by `with_fallbacks` instead.
160
159
  eowarn
@@ -280,7 +279,15 @@ module ActionView
280
279
  # add :html as fallback to :js.
281
280
  def formats=(values)
282
281
  if values
282
+ values = values.dup
283
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
+
284
291
  if values == [:js]
285
292
  values << :html
286
293
  @html_fallback_for_js = true
@@ -48,12 +48,11 @@ module ActionView #:nodoc:
48
48
  find_all(*args).first || raise(MissingTemplate.new(self, *args))
49
49
  end
50
50
 
51
- def find_file(path, prefixes = [], *args)
52
- _find_all(path, prefixes, args, true).first || raise(MissingTemplate.new(self, path, prefixes, *args))
53
- end
51
+ alias :find_file :find
52
+ deprecate :find_file
54
53
 
55
54
  def find_all(path, prefixes = [], *args)
56
- _find_all path, prefixes, args, false
55
+ _find_all path, prefixes, args
57
56
  end
58
57
 
59
58
  def exists?(path, prefixes, *args)
@@ -71,15 +70,11 @@ module ActionView #:nodoc:
71
70
 
72
71
  private
73
72
 
74
- def _find_all(path, prefixes, args, outside_app)
73
+ def _find_all(path, prefixes, args)
75
74
  prefixes = [prefixes] if String === prefixes
76
75
  prefixes.each do |prefix|
77
76
  paths.each do |resolver|
78
- if outside_app
79
- templates = resolver.find_all_anywhere(path, prefix, *args)
80
- else
81
- templates = resolver.find_all(path, prefix, *args)
82
- end
77
+ templates = resolver.find_all(path, prefix, *args)
83
78
  return templates unless templates.empty?
84
79
  end
85
80
  end
@@ -81,7 +81,7 @@ module ActionView
81
81
  initializer "action_view.per_request_digest_cache" do |app|
82
82
  ActiveSupport.on_load(:action_view) do
83
83
  unless ActionView::Resolver.caching?
84
- app.executor.to_run ActionView::Digestor::PerExecutionDigestCacheExpiry
84
+ app.executor.to_run ActionView::CacheExpiry::Executor.new(watcher: app.config.file_watcher)
85
85
  end
86
86
  end
87
87
  end
@@ -17,13 +17,13 @@ module ActionView
17
17
  # Result is a hash with the key represents the
18
18
  # key used for cache lookup and the value is the item
19
19
  # on which the partial is being rendered
20
- keyed_collection = collection_by_cache_keys(view, template)
20
+ keyed_collection, ordered_keys = collection_by_cache_keys(view, template)
21
21
 
22
22
  # Pull all partials from cache
23
23
  # Result is a hash, key matches the entry in
24
24
  # `keyed_collection` where the cache was retrieved and the
25
25
  # value is the value that was present in the cache
26
- cached_partials = collection_cache.read_multi(*keyed_collection.keys)
26
+ cached_partials = collection_cache.read_multi(*keyed_collection.keys)
27
27
  instrumentation_payload[:cache_hits] = cached_partials.size
28
28
 
29
29
  # Extract the items for the keys that are not found
@@ -40,11 +40,15 @@ module ActionView
40
40
  rendered_partials = @collection.empty? ? [] : yield
41
41
 
42
42
  index = 0
43
- fetch_or_cache_partial(cached_partials, template, order_by: keyed_collection.each_key) do
43
+ keyed_partials = fetch_or_cache_partial(cached_partials, template, order_by: keyed_collection.each_key) do
44
44
  # This block is called once
45
45
  # for every cache miss while preserving order.
46
46
  rendered_partials[index].tap { index += 1 }
47
47
  end
48
+
49
+ ordered_keys.map do |key|
50
+ keyed_partials[key]
51
+ end
48
52
  end
49
53
 
50
54
  def callable_cache_key?
@@ -56,8 +60,10 @@ module ActionView
56
60
 
57
61
  digest_path = view.digest_path_from_template(template)
58
62
 
59
- @collection.each_with_object({}) do |item, hash|
60
- hash[expanded_cache_key(seed.call(item), view, template, digest_path)] = item
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
61
67
  end
62
68
  end
63
69
 
@@ -82,15 +88,16 @@ module ActionView
82
88
  # If the partial is not already cached it will also be
83
89
  # written back to the underlying cache store.
84
90
  def fetch_or_cache_partial(cached_partials, template, order_by:)
85
- order_by.map do |cache_key|
86
- if content = cached_partials[cache_key]
87
- build_rendered_template(content, template)
88
- else
89
- yield.tap do |rendered_partial|
90
- collection_cache.write(cache_key, rendered_partial.body)
91
- end
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
92
100
  end
93
- end
94
101
  end
95
102
  end
96
103
  end