aboutsummaryrefslogtreecommitdiffstats
path: root/actionview
diff options
context:
space:
mode:
Diffstat (limited to 'actionview')
-rw-r--r--actionview/CHANGELOG.md2
-rw-r--r--actionview/lib/action_view/digestor.rb22
-rw-r--r--actionview/lib/action_view/helpers/tag_helper.rb1
-rw-r--r--actionview/lib/action_view/renderer/partial_renderer.rb7
-rw-r--r--actionview/lib/action_view/renderer/partial_renderer/collection_caching.rb33
-rw-r--r--actionview/lib/action_view/tasks/dependencies.rake4
-rw-r--r--actionview/test/template/digestor_test.rb39
-rw-r--r--actionview/test/template/tag_helper_test.rb6
8 files changed, 49 insertions, 65 deletions
diff --git a/actionview/CHANGELOG.md b/actionview/CHANGELOG.md
index 256b90784a..bebe78c360 100644
--- a/actionview/CHANGELOG.md
+++ b/actionview/CHANGELOG.md
@@ -68,7 +68,7 @@
*Vasiliy Ermolovich*
-* Add a `hidden_field` on the `collection_radio_buttons` to avoid raising a error
+* Add a `hidden_field` on the `collection_radio_buttons` to avoid raising an error
when the only input on the form is the `collection_radio_buttons`.
*Mauro George*
diff --git a/actionview/lib/action_view/digestor.rb b/actionview/lib/action_view/digestor.rb
index 3a6cf63803..657026fa14 100644
--- a/actionview/lib/action_view/digestor.rb
+++ b/actionview/lib/action_view/digestor.rb
@@ -22,23 +22,23 @@ module ActionView
# * <tt>finder</tt> - An instance of <tt>ActionView::LookupContext</tt>
# * <tt>dependencies</tt> - An array of dependent views
# * <tt>partial</tt> - Specifies whether the template is a partial
- def digest(options)
- options.assert_valid_keys(:name, :finder, :dependencies, :partial)
+ def digest(name:, finder:, **options)
+ options.assert_valid_keys(:dependencies, :partial)
- cache_key = ([ options[:name], options[:finder].details_key.hash ].compact + Array.wrap(options[:dependencies])).join('.')
+ cache_key = ([ name, finder.details_key.hash ].compact + Array.wrap(options[:dependencies])).join('.')
# this is a correctly done double-checked locking idiom
# (Concurrent::Map's lookups have volatile semantics)
@@cache[cache_key] || @@digest_monitor.synchronize do
@@cache.fetch(cache_key) do # re-check under lock
- compute_and_store_digest(cache_key, options)
+ compute_and_store_digest(cache_key, name, finder, options)
end
end
end
private
- def compute_and_store_digest(cache_key, options) # called under @@digest_monitor lock
- klass = if options[:partial] || options[:name].include?("/_")
+ def compute_and_store_digest(cache_key, name, finder, options) # called under @@digest_monitor lock
+ klass = if options[:partial] || name.include?("/_")
# Prevent re-entry or else recursive templates will blow the stack.
# There is no need to worry about other threads seeing the +false+ value,
# as they will then have to wait for this thread to let go of the @@digest_monitor lock.
@@ -48,7 +48,7 @@ module ActionView
Digestor
end
- @@cache[cache_key] = stored_digest = klass.new(options).digest
+ @@cache[cache_key] = stored_digest = klass.new(name, finder, options).digest
ensure
# something went wrong or ActionView::Resolver.caching? is false, make sure not to corrupt the @@cache
@@cache.delete_pair(cache_key, false) if pre_stored && !stored_digest
@@ -57,9 +57,9 @@ module ActionView
attr_reader :name, :finder, :options
- def initialize(options)
- @name, @finder = options.values_at(:name, :finder)
- @options = options.except(:name, :finder)
+ def initialize(name, finder, options = {})
+ @name, @finder = name, finder
+ @options = options
end
def digest
@@ -80,7 +80,7 @@ module ActionView
def nested_dependencies
dependencies.collect do |dependency|
- dependencies = PartialDigestor.new(name: dependency, finder: finder).nested_dependencies
+ dependencies = PartialDigestor.new(dependency, finder).nested_dependencies
dependencies.any? ? { dependency => dependencies } : dependency
end
end
diff --git a/actionview/lib/action_view/helpers/tag_helper.rb b/actionview/lib/action_view/helpers/tag_helper.rb
index 2562504896..42e7358a1d 100644
--- a/actionview/lib/action_view/helpers/tag_helper.rb
+++ b/actionview/lib/action_view/helpers/tag_helper.rb
@@ -154,6 +154,7 @@ module ActionView
options.each_pair do |key, value|
if TAG_PREFIXES.include?(key) && value.is_a?(Hash)
value.each_pair do |k, v|
+ next if v.nil?
output << sep
output << prefix_tag_option(key, k, v, escape)
end
diff --git a/actionview/lib/action_view/renderer/partial_renderer.rb b/actionview/lib/action_view/renderer/partial_renderer.rb
index bdbf03191a..a9bd257e76 100644
--- a/actionview/lib/action_view/renderer/partial_renderer.rb
+++ b/actionview/lib/action_view/renderer/partial_renderer.rb
@@ -428,6 +428,8 @@ module ActionView
layout = find_template(layout, @template_keys)
end
+ collection_cache_eligible = automatic_cache_eligible?
+
partial_iteration = PartialIteration.new(@collection.size)
locals[iteration] = partial_iteration
@@ -436,6 +438,11 @@ module ActionView
locals[counter] = partial_iteration.index
content = template.render(view, locals)
+
+ if collection_cache_eligible
+ collection_cache_rendered_partial(content, object)
+ end
+
content = layout.render(view, locals) { content } if layout
partial_iteration.iterate!
content
diff --git a/actionview/lib/action_view/renderer/partial_renderer/collection_caching.rb b/actionview/lib/action_view/renderer/partial_renderer/collection_caching.rb
index 1147963882..4860f00243 100644
--- a/actionview/lib/action_view/renderer/partial_renderer/collection_caching.rb
+++ b/actionview/lib/action_view/renderer/partial_renderer/collection_caching.rb
@@ -15,13 +15,16 @@ module ActionView
return yield unless cache_collection?
keyed_collection = collection_by_cache_keys
- partial_cache = collection_cache.read_multi(*keyed_collection.keys)
+ cached_partials = collection_cache.read_multi(*keyed_collection.keys)
- @collection = keyed_collection.reject { |key, _| partial_cache.key?(key) }.values
- rendered_partials = @collection.any? ? yield.dup : []
+ @collection = keyed_collection.reject { |key, _| cached_partials.key?(key) }.values
+ rendered_partials = @collection.empty? ? [] : yield
- fetch_or_cache_partial(partial_cache, order_by: keyed_collection.each_key) do
- rendered_partials.shift
+ index = 0
+ keyed_collection.map do |cache_key, _|
+ cached_partials.fetch(cache_key) do
+ rendered_partials[index].tap { index += 1 }
+ end
end
end
@@ -30,12 +33,7 @@ module ActionView
end
def automatic_cache_eligible?
- single_template_render? && !callable_cache_key? &&
- @template.eligible_for_collection_caching?(as: @options[:as])
- end
-
- def single_template_render?
- @template # Template is only set when a collection renders one template.
+ @template && @template.eligible_for_collection_caching?(as: @options[:as])
end
def callable_cache_key?
@@ -55,15 +53,10 @@ module ActionView
key.frozen? ? key.dup : key # #read_multi & #write may require mutability, Dalli 2.6.0.
end
- def fetch_or_cache_partial(cached_partials, order_by:)
- cache_options = @options[:cache_options] || @locals[:cache_options] || {}
-
- order_by.map do |key|
- cached_partials.fetch(key) do
- yield.tap do |rendered_partial|
- collection_cache.write(key, rendered_partial, cache_options)
- end
- end
+ def collection_cache_rendered_partial(rendered_partial, key_by)
+ if callable_cache_key?
+ key = expanded_cache_key(@options[:cache].call(key_by))
+ collection_cache.write(key, rendered_partial, @options[:cache_options])
end
end
end
diff --git a/actionview/lib/action_view/tasks/dependencies.rake b/actionview/lib/action_view/tasks/dependencies.rake
index f394c319c1..9932ff8b6d 100644
--- a/actionview/lib/action_view/tasks/dependencies.rake
+++ b/actionview/lib/action_view/tasks/dependencies.rake
@@ -2,13 +2,13 @@ namespace :cache_digests do
desc 'Lookup nested dependencies for TEMPLATE (like messages/show or comments/_comment.html)'
task :nested_dependencies => :environment do
abort 'You must provide TEMPLATE for the task to run' unless ENV['TEMPLATE'].present?
- puts JSON.pretty_generate ActionView::Digestor.new(name: CacheDigests.template_name, finder: CacheDigests.finder).nested_dependencies
+ puts JSON.pretty_generate ActionView::Digestor.new(CacheDigests.template_name, CacheDigests.finder).nested_dependencies
end
desc 'Lookup first-level dependencies for TEMPLATE (like messages/show or comments/_comment.html)'
task :dependencies => :environment do
abort 'You must provide TEMPLATE for the task to run' unless ENV['TEMPLATE'].present?
- puts JSON.pretty_generate ActionView::Digestor.new(name: CacheDigests.template_name, finder: CacheDigests.finder).dependencies
+ puts JSON.pretty_generate ActionView::Digestor.new(CacheDigests.template_name, CacheDigests.finder).dependencies
end
class CacheDigests
diff --git a/actionview/test/template/digestor_test.rb b/actionview/test/template/digestor_test.rb
index dde757b5a2..bfab97cf1e 100644
--- a/actionview/test/template/digestor_test.rb
+++ b/actionview/test/template/digestor_test.rb
@@ -13,34 +13,11 @@ class FixtureTemplate
end
end
-class FixtureFinder
+class FixtureFinder < ActionView::LookupContext
FIXTURES_DIR = "#{File.dirname(__FILE__)}/../fixtures/digestor"
- attr_reader :details, :view_paths
- attr_accessor :formats
- attr_accessor :variants
-
- def initialize
- @details = {}
- @view_paths = ActionView::PathSet.new(['digestor'])
- @formats = []
- @variants = []
- end
-
- def details_key
- details.hash
- end
-
- def find(name, prefixes = [], partial = false, keys = [], options = {})
- partial_name = partial ? name.gsub(%r|/([^/]+)$|, '/_\1') : name
- format = @formats.first.to_s
- format += "+#{@variants.first}" if @variants.any?
-
- FixtureTemplate.new("digestor/#{partial_name}.#{format}.erb")
- end
-
- def disable_cache(&block)
- yield
+ def initialize(details = {})
+ super(ActionView::PathSet.new(['digestor']), details, [])
end
end
@@ -206,13 +183,14 @@ class TemplateDigestorTest < ActionView::TestCase
def test_details_are_included_in_cache_key
# Cache the template digest.
+ @finder = FixtureFinder.new({:formats => [:html]})
old_digest = digest("events/_event")
# Change the template; the cached digest remains unchanged.
change_template("events/_event")
# The details are changed, so a new cache key is generated.
- finder.details[:foo] = "bar"
+ @finder = FixtureFinder.new
# The cache is busted.
assert_not_equal old_digest, digest("events/_event")
@@ -317,25 +295,24 @@ class TemplateDigestorTest < ActionView::TestCase
yield
- assert previous_digest != digest(template_name, options), "digest didn't change"
+ assert_not_equal previous_digest, digest(template_name, options), "digest didn't change"
ActionView::Digestor.cache.clear
end
def digest(template_name, options = {})
options = options.dup
- finder.formats = [:html]
finder.variants = options.delete(:variants) || []
ActionView::Digestor.digest({ name: template_name, finder: finder }.merge(options))
end
def dependencies(template_name)
- ActionView::Digestor.new({ name: template_name, finder: finder }).dependencies
+ ActionView::Digestor.new(template_name, finder).dependencies
end
def nested_dependencies(template_name)
- ActionView::Digestor.new({ name: template_name, finder: finder }).nested_dependencies
+ ActionView::Digestor.new(template_name, finder).nested_dependencies
end
def finder
diff --git a/actionview/test/template/tag_helper_test.rb b/actionview/test/template/tag_helper_test.rb
index 6f7a78ccef..f3956a31f6 100644
--- a/actionview/test/template/tag_helper_test.rb
+++ b/actionview/test/template/tag_helper_test.rb
@@ -173,4 +173,10 @@ class TagHelperTest < ActionView::TestCase
tag('a', { aria => { a_float: 3.14, a_big_decimal: BigDecimal.new("-123.456"), a_number: 1, string: 'hello', symbol: :foo, array: [1, 2, 3], hash: { key: 'value'}, string_with_quotes: 'double"quote"party"' } })
}
end
+
+ def test_link_to_data_nil_equal
+ div_type1 = content_tag(:div, 'test', { 'data-tooltip' => nil })
+ div_type2 = content_tag(:div, 'test', { data: {tooltip: nil} })
+ assert_dom_equal div_type1, div_type2
+ end
end