From ef61c9c8a378b076d85be0c95cc83863c5a88401 Mon Sep 17 00:00:00 2001 From: Jonathan Hefner Date: Mon, 7 Dec 2020 15:41:44 -0600 Subject: [PATCH] Fix rendering Action Text HTML in new threads Because `ActionText::Content.renderer` is implemented as a `thread_cattr_accessor`, any default value set in the main thread will be inaccessible from other threads. Therefore, use a `cattr_accessor` to store the default renderer, and fall back to it when `renderer` has not been set by e.g. `with_renderer`. Fixes #40757. --- actiontext/lib/action_text/engine.rb | 2 +- actiontext/lib/action_text/rendering.rb | 3 ++- actiontext/test/unit/content_test.rb | 9 +++++++++ 3 files changed, 12 insertions(+), 2 deletions(-) diff --git a/actiontext/lib/action_text/engine.rb b/actiontext/lib/action_text/engine.rb index 9d5fd1dd251..e78c95b69b8 100644 --- a/actiontext/lib/action_text/engine.rb +++ b/actiontext/lib/action_text/engine.rb @@ -46,7 +46,7 @@ module ActionText initializer "action_text.renderer" do ActiveSupport.on_load(:action_text_content) do - self.renderer = Class.new(ActionController::Base).renderer + self.default_renderer = Class.new(ActionController::Base).renderer end %i[action_controller_base action_mailer].each do |abstract_controller| diff --git a/actiontext/lib/action_text/rendering.rb b/actiontext/lib/action_text/rendering.rb index caef71c6b48..47cced4ce5d 100644 --- a/actiontext/lib/action_text/rendering.rb +++ b/actiontext/lib/action_text/rendering.rb @@ -8,6 +8,7 @@ module ActionText extend ActiveSupport::Concern included do + cattr_accessor :default_renderer, instance_accessor: false thread_cattr_accessor :renderer, instance_accessor: false delegate :render, to: :class end @@ -22,7 +23,7 @@ module ActionText end def render(*args, &block) - renderer.render_to_string(*args, &block) + (renderer || default_renderer).render_to_string(*args, &block) end end end diff --git a/actiontext/test/unit/content_test.rb b/actiontext/test/unit/content_test.rb index c00ad181a59..dcedb8b1d46 100644 --- a/actiontext/test/unit/content_test.rb +++ b/actiontext/test/unit/content_test.rb @@ -116,6 +116,15 @@ class ActionText::ContentTest < ActiveSupport::TestCase assert_not defined?(::ApplicationController) end + test "renders with layout when in a new thread" do + html = "

Hello world

" + rendered = nil + Thread.new { rendered = content_from_html(html).to_rendered_html_with_layout }.join + + assert_includes rendered, html + assert_match %r/\A#{Regexp.escape '
'}/, rendered + end + private def content_from_html(html) ActionText::Content.new(html).tap do |content|