我的问题:使用 Hotwire/Turbo 渲染图像时,所有 URL 均使用主机
example.org
渲染,而不是我的实际主机名。常规视图很好,但通过 Turbo 流渲染部分视图会导致 ActiveStorage URL,如 http://example.org/.../
。
上下文:我有一个简单的 Todo 应用程序,带有工作视图、部分视图和涡轮流,它们一起显示 Todo 和关联用户的列表。当我将用户加入 Todo 时,turbo 流会渲染正确的部分,并将用户的姓名和头像放入我想要的 DOM 中。但是,来自 ActiveStorage 的图像 URL 包含
example.org
主机名。
我在
config/environments/*.rb
中设置了我的标准 URL 选项,包括 routes.default_url_options[:host]
和 config.action_mailer.default_url_options[:host]
。我还了解了文件config/initializers/application_controller_renderer.rb
,您可以在其中设置http_host
参数;但是,我已经设置了 http_host
,即 https
布尔值,Turbo 仍然使用 example.org 渲染我的 image_tag
。
此外,我发现有关如何以编程方式操作默认渲染器(为了解决问题)的建议有限。 此来源说要抓取
ApplicationController.renderer
并覆盖属性,如下所示:
renderer = ApplicationController.renderer.new(
http_host: request.host_with_port,
https: (request.protocol == "https://"),
"rack.session": request.session
)
但是
broadcast_action_to
方法似乎不接受 renderer
参数,所以这实际上对 Turbo 中的我没有帮助。
肯定有一个配置我丢失了,但我在 Turbo 或 Hotwire 文档中没有找到它。
我失踪了
config.action_controller.default_url_options
。一旦我将其配置为与其他 default_url_options 相同,我的链接就开始正确呈现。
就我而言,我有一个动态
default_url_options
,因为我的应用程序是多租户的,所以我将其添加到ApplicationController
:
def default_url_options
{ host: SiteSetting[:entity].domains.first.name, protocol: 'https' }
end
我认为这一切都源于
asset_host
配置,因此通常图像 URL 中包含资产主机。 ActiveStorage
url 使用当前的默认主机(当然不是资产主机),因为它们实际上是重定向路由而不是实际文件。我假设如果未设置 asset_host
,那么图像路径将是相对的而不是绝对的?如果无论如何都能让他们保持相对关系那就太理想了。
我们可以直接使用
<%= image_tag url_for(user.avatar) %>
显示 Turbo Stream 中的任何图像。
例如,使用 Turbo Stream 显示实时发布通知,我们可以使用以下代码来发布部分
<!-- app/views/notifications/_post.html.erb -->
<div class="flex items-start space-x-4 bg-white p-4 rounded-lg shadow-md">
<% if notification.item.user.avatar.attached? %>
<%= image_tag url_for(notification.item.user.avatar), class: 'w-10 h-10 rounded-full' %>
<% end %>
<div class="flex-grow">
<p class="text-gray-700">
<span class="font-semibold text-gray-900"><%= notification.item.user.username %></span>
added a new post:
</p>
<p class="mt-1 text-gray-600">
<%= link_to notification.item.content.truncate(100), notification.item, class: "underline text-blue-600 hover:text-blue-800 font-medium" %>
</p>
<p class="text-sm text-gray-400 mt-1">
<%= time_ago_in_words(notification.item.created_at) %> ago
</p>
</div>
<% if notification.item.image.attached? %>
<div class="flex-shrink-0">
<%= image_tag url_for(notification.item.image), class: 'w-20 h-20 object-cover rounded-lg' %>
</div>
<% end %>
</div>