mirror of
https://github.com/rails/rails.git
synced 2022-11-09 12:12:34 -05:00
Disentangle Action Text from ApplicationController
This commit allows Action Text to be used without having an ApplicationController defined. In doing so, it also fixes Action Text attachments to render the correct URL host in mailers. It also avoids allocating an ActionController::Renderer per request. Fixes #37183. Fixes #35578. Fixes #36963. Closes #38714. Co-authored-by: Jeremy Daer <jeremydaer@gmail.com>
This commit is contained in:
parent
80f7fd52b2
commit
614e813161
20 changed files with 139 additions and 31 deletions
|
@ -99,6 +99,7 @@ module ActionController
|
|||
instance.set_response! controller.make_response!(request)
|
||||
instance.render_to_string(*args)
|
||||
end
|
||||
alias_method :render_to_string, :render # :nodoc:
|
||||
|
||||
private
|
||||
def normalize_keys(defaults, env)
|
||||
|
|
|
@ -10,6 +10,7 @@ module ActionText
|
|||
mattr_accessor(:scrubber)
|
||||
|
||||
def render_action_text_content(content)
|
||||
self.prefix_partial_path_with_controller_namespace = false
|
||||
sanitize_action_text_content(render_action_text_attachments(content))
|
||||
end
|
||||
|
||||
|
|
|
@ -16,6 +16,7 @@ module ActionText
|
|||
autoload :Fragment
|
||||
autoload :HtmlConversion
|
||||
autoload :PlainTextConversion
|
||||
autoload :Rendering
|
||||
autoload :Serialization
|
||||
autoload :TrixAttachment
|
||||
|
||||
|
|
|
@ -28,7 +28,7 @@ module ActionText
|
|||
private
|
||||
def trix_attachment_content
|
||||
if partial_path = attachable.try(:to_trix_content_attachment_partial_path)
|
||||
ActionText::Content.renderer.render(partial: partial_path, object: self, as: model_name.element)
|
||||
ActionText::Content.render(partial: partial_path, object: self, as: model_name.element)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,12 +1,8 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require "active_support/core_ext/module/attribute_accessors_per_thread"
|
||||
|
||||
module ActionText
|
||||
class Content
|
||||
include Serialization
|
||||
|
||||
thread_cattr_accessor :renderer
|
||||
include Rendering, Serialization
|
||||
|
||||
attr_reader :fragment
|
||||
|
||||
|
@ -88,7 +84,7 @@ module ActionText
|
|||
end
|
||||
|
||||
def to_rendered_html_with_layout
|
||||
renderer.render(partial: "action_text/content/layout", locals: { content: self })
|
||||
render partial: "action_text/content/layout", locals: { content: self }
|
||||
end
|
||||
|
||||
def to_s
|
||||
|
|
|
@ -37,21 +37,24 @@ module ActionText
|
|||
end
|
||||
|
||||
initializer "action_text.helper" do
|
||||
ActiveSupport.on_load(:action_controller_base) do
|
||||
helper ActionText::Engine.helpers
|
||||
%i[action_controller_base action_mailer].each do |abstract_controller|
|
||||
ActiveSupport.on_load(abstract_controller) do
|
||||
helper ActionText::Engine.helpers
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
initializer "action_text.renderer" do |app|
|
||||
app.executor.to_run { ActionText::Content.renderer = ApplicationController.renderer }
|
||||
app.executor.to_complete { ActionText::Content.renderer = ApplicationController.renderer }
|
||||
|
||||
initializer "action_text.renderer" do
|
||||
ActiveSupport.on_load(:action_text_content) do
|
||||
self.renderer = ApplicationController.renderer
|
||||
self.renderer = Class.new(ActionController::Base).renderer
|
||||
end
|
||||
|
||||
ActiveSupport.on_load(:action_controller_base) do
|
||||
before_action { ActionText::Content.renderer = ApplicationController.renderer.new(request.env) }
|
||||
%i[action_controller_base action_mailer].each do |abstract_controller|
|
||||
ActiveSupport.on_load(abstract_controller) do
|
||||
around_action do |controller, action|
|
||||
ActionText::Content.with_renderer(controller, &action)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
|
29
actiontext/lib/action_text/rendering.rb
Normal file
29
actiontext/lib/action_text/rendering.rb
Normal file
|
@ -0,0 +1,29 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require "active_support/concern"
|
||||
require "active_support/core_ext/module/attribute_accessors_per_thread"
|
||||
|
||||
module ActionText
|
||||
module Rendering #:nodoc:
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
included do
|
||||
thread_cattr_accessor :renderer, instance_accessor: false
|
||||
delegate :render, to: :class
|
||||
end
|
||||
|
||||
class_methods do
|
||||
def with_renderer(renderer)
|
||||
previous_renderer = self.renderer
|
||||
self.renderer = renderer
|
||||
yield
|
||||
ensure
|
||||
self.renderer = previous_renderer
|
||||
end
|
||||
|
||||
def render(*args, &block)
|
||||
renderer.render_to_string(*args, &block)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,5 @@
|
|||
class Admin::MessagesController < ActionController::Base
|
||||
def show
|
||||
@message = Message.find(params[:id])
|
||||
end
|
||||
end
|
|
@ -1,2 +0,0 @@
|
|||
class ApplicationController < ActionController::Base
|
||||
end
|
|
@ -1,4 +1,4 @@
|
|||
class MessagesController < ApplicationController
|
||||
class MessagesController < ActionController::Base
|
||||
before_action :set_message, only: [:show, :edit, :update, :destroy]
|
||||
|
||||
# GET /messages
|
||||
|
|
6
actiontext/test/dummy/app/mailers/messages_mailer.rb
Normal file
6
actiontext/test/dummy/app/mailers/messages_mailer.rb
Normal file
|
@ -0,0 +1,6 @@
|
|||
class MessagesMailer < ApplicationMailer
|
||||
def notification
|
||||
@message = params[:message]
|
||||
mail to: params[:recipient], subject: "NEW MESSAGE: #{@message.subject}"
|
||||
end
|
||||
end
|
16
actiontext/test/dummy/app/views/admin/messages/show.html.erb
Normal file
16
actiontext/test/dummy/app/views/admin/messages/show.html.erb
Normal file
|
@ -0,0 +1,16 @@
|
|||
<dl>
|
||||
<dt>Subject</dt>
|
||||
<dd>
|
||||
<span id="subject"><%= @message.subject %></span>
|
||||
</dd>
|
||||
|
||||
<dt>Content (Plain Text)</dt>
|
||||
<dd>
|
||||
<pre id="content-plain"><%= @message.content.to_plain_text %></pre>
|
||||
</dd>
|
||||
|
||||
<dt>Content (HTML)</dt>
|
||||
<dd>
|
||||
<div id="content-html"><%= @message.content %></div>
|
||||
</dd>
|
||||
</dl>
|
|
@ -3,9 +3,6 @@
|
|||
<head>
|
||||
<title>Dummy</title>
|
||||
<%= csrf_meta_tags %>
|
||||
|
||||
<%= stylesheet_link_tag 'application', media: 'all' %>
|
||||
<%= javascript_pack_tag 'application' %>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
|
|
@ -1,13 +1,8 @@
|
|||
<p id="notice"><%= notice %></p>
|
||||
|
||||
<p>
|
||||
<strong>Subject:</strong>
|
||||
<%= @message.subject %>
|
||||
</p>
|
||||
<h1 id="subject"><%= @message.subject %></h1>
|
||||
|
||||
<div class="trix-content">
|
||||
<%= @message.content.html_safe %>
|
||||
</div>
|
||||
<div id="content"><%= @message.content %></div>
|
||||
|
||||
<%= link_to 'Edit', edit_message_path(@message) %> |
|
||||
<%= link_to 'Back', messages_path %>
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
<div id="message-content"><%= @message.content %></div>
|
|
@ -1,4 +1,7 @@
|
|||
Rails.application.routes.draw do
|
||||
resources :messages
|
||||
# For details on the DSL available within this file, see https://guides.rubyonrails.org/routing.html
|
||||
|
||||
namespace :admin do
|
||||
resources :messages, only: [:show]
|
||||
end
|
||||
end
|
||||
|
|
24
actiontext/test/integration/controller_render_test.rb
Normal file
24
actiontext/test/integration/controller_render_test.rb
Normal file
|
@ -0,0 +1,24 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require "test_helper"
|
||||
|
||||
class ActionText::ControllerRenderTest < ActionDispatch::IntegrationTest
|
||||
test "uses current request environment" do
|
||||
blob = create_file_blob(filename: "racecar.jpg", content_type: "image/jpg")
|
||||
message = Message.create!(content: ActionText::Content.new.append_attachables(blob))
|
||||
|
||||
host! "loocalhoost"
|
||||
get message_path(message)
|
||||
assert_select "#content img" do |imgs|
|
||||
imgs.each { |img| assert_match %r"//loocalhoost/", img["src"] }
|
||||
end
|
||||
end
|
||||
|
||||
test "resolves partials when controller is namespaced" do
|
||||
blob = create_file_blob(filename: "racecar.jpg", content_type: "image/jpg")
|
||||
message = Message.create!(content: ActionText::Content.new.append_attachables(blob))
|
||||
|
||||
get admin_message_path(message)
|
||||
assert_select "#content-html .trix-content .attachment--jpg"
|
||||
end
|
||||
end
|
23
actiontext/test/integration/mailer_render_test.rb
Normal file
23
actiontext/test/integration/mailer_render_test.rb
Normal file
|
@ -0,0 +1,23 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require "test_helper"
|
||||
|
||||
class ActionText::MailerRenderTest < ActionMailer::TestCase
|
||||
test "uses default_url_options" do
|
||||
original_default_url_options = ActionMailer::Base.default_url_options
|
||||
ActionMailer::Base.default_url_options = { host: "hoost" }
|
||||
|
||||
blob = create_file_blob(filename: "racecar.jpg", content_type: "image/jpg")
|
||||
message = Message.new(content: ActionText::Content.new.append_attachables(blob))
|
||||
|
||||
MessagesMailer.with(recipient: "test", message: message).notification.deliver_now
|
||||
|
||||
assert_select_email do
|
||||
assert_select "#message-content img" do |imgs|
|
||||
imgs.each { |img| assert_match %r"//hoost/", img["src"] }
|
||||
end
|
||||
end
|
||||
ensure
|
||||
ActionMailer::Base.default_url_options = original_default_url_options
|
||||
end
|
||||
end
|
|
@ -107,6 +107,15 @@ class ActionText::ContentTest < ActiveSupport::TestCase
|
|||
assert_equal "<blockquote><div>#{attachment_html}</div></blockquote>", content_from_html(html).to_html
|
||||
end
|
||||
|
||||
test "renders with layout when ApplicationController is not defined" do
|
||||
html = "<h1>Hello world</h1>"
|
||||
rendered = content_from_html(html).to_rendered_html_with_layout
|
||||
|
||||
assert_includes rendered, html
|
||||
assert_match %r/\A#{Regexp.escape '<div class="trix-content">'}/, rendered
|
||||
assert_not defined?(::ApplicationController)
|
||||
end
|
||||
|
||||
private
|
||||
def content_from_html(html)
|
||||
ActionText::Content.new(html).tap do |content|
|
||||
|
|
|
@ -151,7 +151,7 @@ module ActionView #:nodoc:
|
|||
# Specify whether rendering within namespaced controllers should prefix
|
||||
# the partial paths for ActiveModel objects with the namespace.
|
||||
# (e.g., an Admin::PostsController would render @post using /admin/posts/_post.erb)
|
||||
cattr_accessor :prefix_partial_path_with_controller_namespace, default: true
|
||||
class_attribute :prefix_partial_path_with_controller_namespace, default: true
|
||||
|
||||
# Specify default_formats that can be rendered.
|
||||
cattr_accessor :default_formats
|
||||
|
|
Loading…
Reference in a new issue