Skip to content

Fix Action View collection caching to store fragments as bare strings #48645

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jul 5, 2023

Conversation

casperisfine
Copy link
Contributor

Ref: #48611

Individual fragments have been cached as bare string since forever, but somehow fragment cached via collection caching were stored as ActionView::OutputBuffer instances.

This is both bad for performance, but also can cause issues on Rails upgrades if the internal representation of AV::OutputBuffer changes.

I think we should consider this PR as a bug fix, and backport it accordingly.

cc @matthewd, @matthutchinson, @skipkayhil

if content = cached_partials[cache_key]
build_rendered_template(content, template)
else
yield.tap do |rendered_partial|
collection_cache.write(cache_key, rendered_partial.body)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

While I was at it, I converted this write loop into a single write_multi.

@@ -9,7 +9,7 @@ module CollectionCaching # :nodoc:
included do
# Fallback cache store if Action View is used without Rails.
# Otherwise overridden in Railtie to use Rails.cache.
mattr_accessor :collection_cache, default: ActiveSupport::Cache::MemoryStore.new
mattr_accessor :collection_cache, default: ActiveSupport::Cache::NullStore.new
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This definitely doesn't sound backportable

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's not strictly necessary, just seemed weird to me. I'll revert it.

collection_cache.write(cache_key, rendered_partial.body)
end
rendered_partial = yield
entries_to_write[cache_key] = rendered_partial.body.to_str
Copy link
Member

@matthewd matthewd Jul 4, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is body absolutely definitely 150% guaranteed to be an OutputBuffer (or String) here, even given a particularly pathological template renderer etc?

(This is both "can we assume there's a to_str?", and "are we allowed to force the value to a string?")


Sorry this is a lazy "I haven't read the context" question, but I imagine the answer is likely "yes I have already read and checked that", in which case it's easier for me to just ask. 😅

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nah, it was a good question. It appears that EmptyCollection#body returns nil for instance.

However I do think we can enforce nil or respond_to?(:to_str).

@casperisfine casperisfine force-pushed the action-view-bare-cache-fragments branch from 9015335 to 5e916e7 Compare July 4, 2023 14:34
Ref: rails#48611

Individual fragments have been cached as bare string since forever,
but somehow fragment cached via collection caching were stored
as `ActionView::OutputBuffer` instances.

This is both bad for performance, but also can cause issues on
Rails upgrades if the internal representation of `AV::OutputBuffer`
changes.
@casperisfine casperisfine force-pushed the action-view-bare-cache-fragments branch from 5e916e7 to 6842e76 Compare July 4, 2023 14:37
@casperisfine casperisfine requested a review from matthewd July 4, 2023 14:47
@byroot byroot merged commit 76deaf6 into rails:main Jul 5, 2023
casperisfine pushed a commit to Shopify/rails that referenced this pull request Jul 5, 2023
…agments

Fix Action View collection caching to store fragments as bare strings
@byroot
Copy link
Member

byroot commented Jul 5, 2023

Backported as 64bd0ac

@edariedl
Copy link

@casperisfine Hi, it broke our application when caching is used with Jbuilder gem https://github.com/rails/jbuilder.

We are getting:

# actionview (7.0.7) lib/action_view/renderer/partial_renderer/collection_caching.rb in block in fetch_or_cache_partial at line 98

ActionView::Template::Error
undefined method `to_str' for {"id"=>1242, "custom_id"=>"abcd123"}:Hash

            if fragment = rendered_partial.body&.to_str
                                               ^^^^^^^^
Did you mean?  to_set
               to_s

@byroot
Copy link
Member

byroot commented Aug 14, 2023

@edariedl, could you share a longer backtrace please?

jbuilder is very annoying, it always break assumptions about views...

@edariedl
Copy link

@byroot yeah sure, here is the full stack trace:

NoMethodError: undefined method `to_str' for {"id"=>123456, "custom_id"=>"abc123"}:Hash

            if fragment = rendered_partial.body&.to_str
                                               ^^^^^^^^
Did you mean?  to_set
               to_s
  from actionview (7.0.7) lib/action_view/renderer/partial_renderer/collection_caching.rb:98:in `block in fetch_or_cache_partial'
  from activesupport (7.0.7) lib/active_support/core_ext/enumerable.rb:134:in `block in index_with'
  from activesupport (7.0.7) lib/active_support/core_ext/enumerable.rb:134:in `each_key'
  from activesupport (7.0.7) lib/active_support/core_ext/enumerable.rb:134:in `each'
  from activesupport (7.0.7) lib/active_support/core_ext/enumerable.rb:134:in `index_with'
  from actionview (7.0.7) lib/action_view/renderer/partial_renderer/collection_caching.rb:93:in `fetch_or_cache_partial'
  from actionview (7.0.7) lib/action_view/renderer/partial_renderer/collection_caching.rb:43:in `cache_collection_render'
  from actionview (7.0.7) lib/action_view/renderer/collection_renderer.rb:161:in `block in render_collection'
  from activesupport (7.0.7) lib/active_support/notifications.rb:206:in `block in instrument'
  from activesupport (7.0.7) lib/active_support/notifications/instrumenter.rb:24:in `instrument'
  from activesupport (7.0.7) lib/active_support/notifications.rb:206:in `instrument'
  from actionview (7.0.7) lib/action_view/renderer/collection_renderer.rb:147:in `render_collection'
  from actionview (7.0.7) lib/action_view/renderer/collection_renderer.rb:119:in `render_collection_with_partial'
  from jbuilder (2.11.5) lib/jbuilder/jbuilder_template.rb:159:in `_render_partial_with_options'
  from jbuilder (2.11.5) lib/jbuilder/jbuilder_template.rb:262:in `_render_explicit_partial'
  from jbuilder (2.11.5) lib/jbuilder/jbuilder_template.rb:55:in `partial!'
  from jbuilder (2.11.5) lib/jbuilder/jbuilder_template.rb:121:in `array!'
  from app/views/api/v2/invoices/index.json.jbuilder:3
  from actionview (7.0.7) lib/action_view/base.rb:244:in `public_send'
  from actionview (7.0.7) lib/action_view/base.rb:244:in `_run'
  from actionview (7.0.7) lib/action_view/template.rb:157:in `block in render'
  from activesupport (7.0.7) lib/active_support/notifications.rb:206:in `block in instrument'
  from activesupport (7.0.7) lib/active_support/notifications/instrumenter.rb:24:in `instrument'
  from activesupport (7.0.7) lib/active_support/notifications.rb:206:in `instrument'
  from actionview (7.0.7) lib/action_view/template.rb:361:in `instrument_render_template'
  from actionview (7.0.7) lib/action_view/template.rb:155:in `render'
  from actionview (7.0.7) lib/action_view/renderer/template_renderer.rb:65:in `block (2 levels) in render_template'
  from activesupport (7.0.7) lib/active_support/notifications.rb:206:in `block in instrument'
  from activesupport (7.0.7) lib/active_support/notifications/instrumenter.rb:24:in `instrument'
  from activesupport (7.0.7) lib/active_support/notifications.rb:206:in `instrument'
  from actionview (7.0.7) lib/action_view/renderer/template_renderer.rb:60:in `block in render_template'
  from actionview (7.0.7) lib/action_view/renderer/template_renderer.rb:79:in `render_with_layout'
  from actionview (7.0.7) lib/action_view/renderer/template_renderer.rb:59:in `render_template'
  from actionview (7.0.7) lib/action_view/renderer/template_renderer.rb:11:in `render'
  from actionview (7.0.7) lib/action_view/renderer/renderer.rb:61:in `render_template_to_object'
  from actionview (7.0.7) lib/action_view/renderer/renderer.rb:29:in `render_to_object'
  from actionview (7.0.7) lib/action_view/rendering.rb:117:in `block in _render_template'
  from actionview (7.0.7) lib/action_view/base.rb:270:in `in_rendering_context'
  from actionview (7.0.7) lib/action_view/rendering.rb:116:in `_render_template'
  from actionpack (7.0.7) lib/action_controller/metal/streaming.rb:216:in `_render_template'
  from actionview (7.0.7) lib/action_view/rendering.rb:103:in `render_to_body'
  from actionpack (7.0.7) lib/action_controller/metal/rendering.rb:158:in `render_to_body'
  from actionpack (7.0.7) lib/action_controller/metal/renderers.rb:141:in `render_to_body'
  from actionpack (7.0.7) lib/abstract_controller/rendering.rb:27:in `render'
  from actionpack (7.0.7) lib/action_controller/metal/rendering.rb:139:in `render'
  from actionpack (7.0.7) lib/action_controller/metal/instrumentation.rb:22:in `block (2 levels) in render'
  from benchmark.rb:311:in `realtime'
  from activesupport (7.0.7) lib/active_support/core_ext/benchmark.rb:14:in `ms'
  from actionpack (7.0.7) lib/action_controller/metal/instrumentation.rb:22:in `block in render'
  from actionpack (7.0.7) lib/action_controller/metal/instrumentation.rb:91:in `cleanup_view_runtime'
  from activerecord (7.0.7) lib/active_record/railties/controller_runtime.rb:34:in `cleanup_view_runtime'
  from elasticsearch-rails (7.2.1) lib/elasticsearch/rails/instrumentation/controller_runtime.rb:37:in `cleanup_view_runtime'
  from actionpack (7.0.7) lib/action_controller/metal/instrumentation.rb:21:in `render'
  from app/controllers/api/v2/invoices_controller.rb:86:in `block (2 levels) in search'
  from responders (3.1.0) lib/action_controller/responder.rb:241:in `default_render'
  from responders (3.1.0) lib/action_controller/responder.rb:193:in `to_format'
  from responders (3.1.0) lib/action_controller/responder.rb:168:in `respond'
  from responders (3.1.0) lib/action_controller/responder.rb:161:in `call'
  from responders (3.1.0) lib/action_controller/respond_with.rb:216:in `respond_with'
  from app/controllers/api/v2/invoices_controller.rb:82:in `search'
  from actionpack (7.0.7) lib/action_controller/metal/basic_implicit_render.rb:6:in `send_action'
  from actionpack (7.0.7) lib/abstract_controller/base.rb:215:in `process_action'
  from actionpack (7.0.7) lib/action_controller/metal/rendering.rb:165:in `process_action'
  from actionpack (7.0.7) lib/abstract_controller/callbacks.rb:234:in `block in process_action'
  from activesupport (7.0.7) lib/active_support/callbacks.rb:118:in `block in run_callbacks'
  from sentry-rails (5.10.0) lib/sentry/rails/controller_transaction.rb:28:in `block in sentry_around_action'
  from sentry-ruby (5.10.0) lib/sentry/hub.rb:102:in `with_child_span'
  from sentry-ruby (5.10.0) lib/sentry-ruby.rb:456:in `with_child_span'
  from sentry-rails (5.10.0) lib/sentry/rails/controller_transaction.rb:14:in `sentry_around_action'
  from activesupport (7.0.7) lib/active_support/callbacks.rb:127:in `block in run_callbacks'
  from activesupport (7.0.7) lib/active_support/callbacks.rb:138:in `run_callbacks'
  from actionpack (7.0.7) lib/abstract_controller/callbacks.rb:233:in `process_action'
  from actionpack (7.0.7) lib/action_controller/metal/rescue.rb:23:in `process_action'
  from actionpack (7.0.7) lib/action_controller/metal/instrumentation.rb:67:in `block in process_action'
  from activesupport (7.0.7) lib/active_support/notifications.rb:206:in `block in instrument'
  from activesupport (7.0.7) lib/active_support/notifications/instrumenter.rb:24:in `instrument'
  from activesupport (7.0.7) lib/active_support/notifications.rb:206:in `instrument'
  from actionpack (7.0.7) lib/action_controller/metal/instrumentation.rb:66:in `process_action'
  from actionpack (7.0.7) lib/action_controller/metal/params_wrapper.rb:259:in `process_action'
  from activerecord (7.0.7) lib/active_record/railties/controller_runtime.rb:27:in `process_action'
  from actionpack (7.0.7) lib/abstract_controller/base.rb:151:in `process'
  from actionview (7.0.7) lib/action_view/rendering.rb:39:in `process'
  from actionpack (7.0.7) lib/action_controller/metal.rb:188:in `dispatch'
  from actionpack (7.0.7) lib/action_controller/metal.rb:251:in `dispatch'
  from actionpack (7.0.7) lib/action_dispatch/routing/route_set.rb:49:in `dispatch'
  from actionpack (7.0.7) lib/action_dispatch/routing/route_set.rb:32:in `serve'
  from actionpack (7.0.7) lib/action_dispatch/journey/router.rb:50:in `block in serve'
  from actionpack (7.0.7) lib/action_dispatch/journey/router.rb:32:in `each'
  from actionpack (7.0.7) lib/action_dispatch/journey/router.rb:32:in `serve'
  from actionpack (7.0.7) lib/action_dispatch/routing/route_set.rb:852:in `call'
  from newrelic_rpm (9.3.1) lib/new_relic/agent/instrumentation/middleware_tracing.rb:99:in `call'
  from newrelic_rpm (9.3.1) lib/new_relic/rack/agent_hooks.rb:30:in `traced_call'
  from newrelic_rpm (9.3.1) lib/new_relic/agent/instrumentation/middleware_tracing.rb:99:in `call'
  from newrelic_rpm (9.3.1) lib/new_relic/rack/browser_monitoring.rb:38:in `traced_call'
  from newrelic_rpm (9.3.1) lib/new_relic/agent/instrumentation/middleware_tracing.rb:99:in `call'
  from rack (2.2.8) lib/rack/tempfile_reaper.rb:15:in `call'
  from newrelic_rpm (9.3.1) lib/new_relic/agent/instrumentation/middleware_tracing.rb:99:in `call'
  from rack (2.2.8) lib/rack/etag.rb:27:in `call'
  from newrelic_rpm (9.3.1) lib/new_relic/agent/instrumentation/middleware_tracing.rb:99:in `call'
  from rack (2.2.8) lib/rack/conditional_get.rb:27:in `call'
  from newrelic_rpm (9.3.1) lib/new_relic/agent/instrumentation/middleware_tracing.rb:99:in `call'
  from rack (2.2.8) lib/rack/head.rb:12:in `call'
  from newrelic_rpm (9.3.1) lib/new_relic/agent/instrumentation/middleware_tracing.rb:99:in `call'
  from actionpack (7.0.7) lib/action_dispatch/http/permissions_policy.rb:38:in `call'
  from newrelic_rpm (9.3.1) lib/new_relic/agent/instrumentation/middleware_tracing.rb:99:in `call'
  from actionpack (7.0.7) lib/action_dispatch/http/content_security_policy.rb:36:in `call'
  from newrelic_rpm (9.3.1) lib/new_relic/agent/instrumentation/middleware_tracing.rb:99:in `call'
  from rack (2.2.8) lib/rack/session/abstract/id.rb:266:in `context'
  from rack (2.2.8) lib/rack/session/abstract/id.rb:260:in `call'
  from newrelic_rpm (9.3.1) lib/new_relic/agent/instrumentation/middleware_tracing.rb:99:in `call'
  from actionpack (7.0.7) lib/action_dispatch/middleware/cookies.rb:704:in `call'
  from newrelic_rpm (9.3.1) lib/new_relic/agent/instrumentation/middleware_tracing.rb:99:in `call'
  from actionpack (7.0.7) lib/action_dispatch/middleware/callbacks.rb:27:in `block in call'
  from activesupport (7.0.7) lib/active_support/callbacks.rb:99:in `run_callbacks'
  from actionpack (7.0.7) lib/action_dispatch/middleware/callbacks.rb:26:in `call'
  from newrelic_rpm (9.3.1) lib/new_relic/agent/instrumentation/middleware_tracing.rb:99:in `call'
  from lib/middleware/rescue_invalid_json_request.rb:9:in `call'
  from newrelic_rpm (9.3.1) lib/new_relic/agent/instrumentation/middleware_tracing.rb:99:in `call'
  from sentry-rails (5.10.0) lib/sentry/rails/rescued_exception_interceptor.rb:12:in `call'
  from newrelic_rpm (9.3.1) lib/new_relic/agent/instrumentation/middleware_tracing.rb:99:in `call'
  from actionpack (7.0.7) lib/action_dispatch/middleware/debug_exceptions.rb:28:in `call'
  from newrelic_rpm (9.3.1) lib/new_relic/agent/instrumentation/middleware_tracing.rb:99:in `call'
  from sentry-ruby (5.10.0) lib/sentry/rack/capture_exceptions.rb:28:in `block (2 levels) in call'
  from sentry-ruby (5.10.0) lib/sentry/hub.rb:227:in `with_session_tracking'
  from sentry-ruby (5.10.0) lib/sentry-ruby.rb:385:in `with_session_tracking'
  from sentry-ruby (5.10.0) lib/sentry/rack/capture_exceptions.rb:19:in `block in call'
  from sentry-ruby (5.10.0) lib/sentry/hub.rb:59:in `with_scope'
  from sentry-ruby (5.10.0) lib/sentry-ruby.rb:365:in `with_scope'
  from sentry-ruby (5.10.0) lib/sentry/rack/capture_exceptions.rb:18:in `call'
  from newrelic_rpm (9.3.1) lib/new_relic/agent/instrumentation/middleware_tracing.rb:99:in `call'
  from actionpack (7.0.7) lib/action_dispatch/middleware/show_exceptions.rb:29:in `call'
  from newrelic_rpm (9.3.1) lib/new_relic/agent/instrumentation/middleware_tracing.rb:99:in `call'
  from lograge (0.13.0) lib/lograge/rails_ext/rack/logger.rb:18:in `call_app'
  from railties (7.0.7) lib/rails/rack/logger.rb:25:in `block in call'
  from activesupport (7.0.7) lib/active_support/tagged_logging.rb:99:in `block in tagged'
  from activesupport (7.0.7) lib/active_support/tagged_logging.rb:37:in `tagged'
  from activesupport (7.0.7) lib/active_support/tagged_logging.rb:99:in `tagged'
  from railties (7.0.7) lib/rails/rack/logger.rb:25:in `call'
  from newrelic_rpm (9.3.1) lib/new_relic/agent/instrumentation/middleware_tracing.rb:99:in `call'
  from actionpack (7.0.7) lib/action_dispatch/middleware/remote_ip.rb:93:in `call'
  from newrelic_rpm (9.3.1) lib/new_relic/agent/instrumentation/middleware_tracing.rb:99:in `call'
  from request_store (1.5.1) lib/request_store/middleware.rb:19:in `call'
  from newrelic_rpm (9.3.1) lib/new_relic/agent/instrumentation/middleware_tracing.rb:99:in `call'
  from actionpack (7.0.7) lib/action_dispatch/middleware/request_id.rb:26:in `call'
  from newrelic_rpm (9.3.1) lib/new_relic/agent/instrumentation/middleware_tracing.rb:99:in `call'
  from rack (2.2.8) lib/rack/method_override.rb:24:in `call'
  from newrelic_rpm (9.3.1) lib/new_relic/agent/instrumentation/middleware_tracing.rb:99:in `call'
  from rack (2.2.8) lib/rack/runtime.rb:22:in `call'
  from newrelic_rpm (9.3.1) lib/new_relic/agent/instrumentation/middleware_tracing.rb:99:in `call'
  from rack-timeout (0.6.3) lib/rack/timeout/core.rb:148:in `block in call'
  from rack-timeout (0.6.3) lib/rack/timeout/support/timeout.rb:19:in `timeout'
  from rack-timeout (0.6.3) lib/rack/timeout/core.rb:147:in `call'
  from newrelic_rpm (9.3.1) lib/new_relic/agent/instrumentation/middleware_tracing.rb:99:in `call'
  from activesupport (7.0.7) lib/active_support/cache/strategy/local_cache_middleware.rb:29:in `call'
  from newrelic_rpm (9.3.1) lib/new_relic/agent/instrumentation/middleware_tracing.rb:99:in `call'
  from actionpack (7.0.7) lib/action_dispatch/middleware/executor.rb:14:in `call'
  from newrelic_rpm (9.3.1) lib/new_relic/agent/instrumentation/middleware_tracing.rb:99:in `call'
  from rack (2.2.8) lib/rack/sendfile.rb:110:in `call'
  from newrelic_rpm (9.3.1) lib/new_relic/agent/instrumentation/middleware_tracing.rb:99:in `call'
  from actionpack (7.0.7) lib/action_dispatch/middleware/ssl.rb:77:in `call'
  from newrelic_rpm (9.3.1) lib/new_relic/agent/instrumentation/middleware_tracing.rb:99:in `call'
  from actionpack (7.0.7) lib/action_dispatch/middleware/host_authorization.rb:137:in `call'
  from newrelic_rpm (9.3.1) lib/new_relic/agent/instrumentation/middleware_tracing.rb:99:in `call'
  from railties (7.0.7) lib/rails/engine.rb:530:in `call'
  from railties (7.0.7) lib/rails/railtie.rb:226:in `public_send'
  from railties (7.0.7) lib/rails/railtie.rb:226:in `method_missing'
  from newrelic_rpm (9.3.1) lib/new_relic/agent/instrumentation/middleware_tracing.rb:99:in `call'
  from puma (6.3.0) lib/puma/configuration.rb:270:in `call'
  from puma (6.3.0) lib/puma/request.rb:100:in `block in handle_request'
  from puma (6.3.0) lib/puma/thread_pool.rb:344:in `with_force_shutdown'
  from puma (6.3.0) lib/puma/request.rb:99:in `handle_request'
  from puma (6.3.0) lib/puma/server.rb:443:in `process_client'
  from puma (6.3.0) lib/puma/server.rb:245:in `block in run'
  from puma (6.3.0) lib/puma/thread_pool.rb:151:in `block in spawn_thread'
  from newrelic_rpm (9.3.1) lib/new_relic/agent/tracer.rb:434:in `block (2 levels) in thread_block_with_current_transaction'
  from newrelic_rpm (9.3.1) lib/new_relic/agent/tracer.rb:356:in `capture_segment_error'
  from newrelic_rpm (9.3.1) lib/new_relic/agent/tracer.rb:433:in `block in thread_block_with_current_transaction'

Thank you for looking at it 🙏.

Is there an alternative to jbuilder? Once in a while we look for something to replace it but it is very convenient to use for JSON API responses.

casperisfine pushed a commit to Shopify/rails that referenced this pull request Aug 14, 2023
Followup: rails#48645

Some template engines such as `jbuilder` use these Action View primitives
with types other than strings, which breaks a bunch of assumptions.

I wish I could add a test for this, but this is deep in private methods
I don't see a way to cover this.
casperisfine pushed a commit to Shopify/rails that referenced this pull request Aug 14, 2023
Followup: rails#48645

Some template engines such as `jbuilder` use these Action View primitives
with types other than strings, which breaks a bunch of assumptions.

I wish I could add a test for this, but this is deep in private methods
I don't see a way to cover this.
@jdelStrother
Copy link
Contributor

I think the switch to write_multi also breaks Rails cache when using Redis::Distributed - eg with

      config.cache_store = :redis_cache_store, {
        url: [url1, url2],
        ...
      }
}

I'm seeing MAPPED_MSET cannot be used in Redis::Distributed because the keys involved need to be on the same server or because we cannot guarantee that the operation will be atomic.

redis (5.0.7) lib/redis/distributed.rb in mapped_mset at line 306
activesupport (7.0.7) lib/active_support/cache/redis_cache_store.rb in block (2 levels) in write_multi_entries at line 419
connection_pool (2.4.1) lib/connection_pool.rb in block (2 levels) in with at line 110
connection_pool (2.4.1) lib/connection_pool.rb in handle_interrupt at line 109
connection_pool (2.4.1) lib/connection_pool.rb in block in with at line 109
connection_pool (2.4.1) lib/connection_pool.rb in handle_interrupt at line 106
connection_pool (2.4.1) lib/connection_pool.rb in with at line 106
activesupport (7.0.7) lib/active_support/cache/redis_cache_store.rb in block in write_multi_entries at line 418
activesupport (7.0.7) lib/active_support/cache/redis_cache_store.rb in failsafe at line 466
activesupport (7.0.7) lib/active_support/cache/redis_cache_store.rb in write_multi_entries at line 416
activesupport (7.0.7) lib/active_support/cache.rb in block in write_multi at line 415
activesupport (7.0.7) lib/active_support/cache.rb in block in instrument at line 783
activesupport (7.0.7) lib/active_support/notifications.rb in block in instrument at line 206
activesupport (7.0.7) lib/active_support/notifications/instrumenter.rb in instrument at line 24
activesupport (7.0.7) lib/active_support/notifications.rb in instrument at line 206
activesupport (7.0.7) lib/active_support/cache.rb in instrument at line 783
activesupport (7.0.7) lib/active_support/cache.rb in write_multi at line 410
actionview (7.0.7) lib/action_view/renderer/partial_renderer/collection_caching.rb in fetch_or_cache_partial at line 106
actionview (7.0.7) lib/action_view/renderer/partial_renderer/collection_caching.rb in cache_collection_render at line 43
actionview (7.0.7) lib/action_view/renderer/collection_renderer.rb in block in render_collection at line 161
activesupport (7.0.7) lib/active_support/notifications.rb in block in instrument at line 206
activesupport (7.0.7) lib/active_support/notifications/instrumenter.rb in instrument at line 24
activesupport (7.0.7) lib/active_support/notifications.rb in instrument at line 206
actionview (7.0.7) lib/action_view/renderer/collection_renderer.rb in render_collection at line 147
actionview (7.0.7) lib/action_view/renderer/collection_renderer.rb in render_collection_with_partial at line 119
actionview (7.0.7) lib/action_view/renderer/renderer.rb in render_partial_to_object at line 72
actionview (7.0.7) lib/action_view/renderer/renderer.rb in render_to_object at line 27
actionview (7.0.7) lib/action_view/renderer/renderer.rb in render at line 22
actionview (7.0.7) lib/action_view/helpers/rendering_helper.rb in block in render at line 37
actionview (7.0.7) lib/action_view/base.rb in in_rendering_context at line 270
actionview (7.0.7) lib/action_view/helpers/rendering_helper.rb in render at line 33

Want me to open it as a separate issue?

@byroot
Copy link
Member

byroot commented Aug 14, 2023

Want me to open it as a separate issue?

Yes. IMO this is a limitation of RedisCacheStore when using Redis::Distributed, we shouldn't make multiple individual writes to work around it.

It should either be documented as a limitation, or fixed in RedisCacheStore / Redis::Distributed.

paulreece pushed a commit to paulreece/rails-paulreece that referenced this pull request Aug 26, 2023
Followup: rails#48645

Some template engines such as `jbuilder` use these Action View primitives
with types other than strings, which breaks a bunch of assumptions.

I wish I could add a test for this, but this is deep in private methods
I don't see a way to cover this.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants