renderpartial不渲染布局



我有一个动作show,它也有一个相应的show.html.erb文件。我要做的是加上"提前回报"所以在记录不存在的情况下说:

class MessagesController < ApplicationController
def show
unless Message.exists?(mid: params[:id])
return render partial: 'messages/expired'
end
# rendered by views/messages/show.html.erb
end
...

如果消息存在,这工作得很好,我可以看到rails渲染所有的文件/布局:

19:51:19 web.1  |   Message Exists? (0.3ms)  SELECT 1 AS one FROM "messages" WHERE "messages"."mid" = $1 LIMIT $2  [["mid", "01G7FD3BBGE2EJH3ABVC5RRWAG"], ["LIMIT", 1]]
19:51:19 web.1  |   ↳ app/controllers/messages_controller.rb:3:in `show'
19:51:19 web.1  |   Rendering layout layouts/application.html.erb
19:51:19 web.1  |   Rendering messages/show.html.erb within layouts/application
19:51:19 web.1  |   Rendered messages/show.html.erb within layouts/application (Duration: 1.9ms | Allocations: 1159)
19:51:19 web.1  |   Rendered layouts/_nav.html.erb (Duration: 0.4ms | Allocations: 129)
19:51:19 web.1  |   Rendered layout layouts/application.html.erb (Duration: 82.3ms | Allocations: 26506)
19:51:19 web.1  | Completed 200 OK in 94ms (Views: 88.6ms | ActiveRecord: 2.6ms | Allocations: 29578)

但是这里有一个奇怪的事情:如果记录不存在,Rails会渲染部分,但是只渲染部分:

19:52:56 web.1  |   Message Exists? (0.6ms)  SELECT 1 AS one FROM "messages" WHERE "messages"."mid" = $1 LIMIT $2  [["mid", "01G7FD3BBGE2EJH3ABVC5RRWA"], ["LIMIT", 1]]
19:52:56 web.1  |   ↳ app/controllers/messages_controller.rb:3:in `show'
19:52:56 web.1  |   Rendered messages/_expired.html.erb (Duration: 0.1ms | Allocations: 22)
19:52:56 web.1  | Completed 200 OK in 10ms (Views: 1.3ms | ActiveRecord: 0.6ms | Allocations: 885)
19:52:56 web.1  |

我不记得以前见过这种行为,所以我真的很困惑…我做错了什么?老实说,我有点累了,所以可能是我看不见眼前的东西,但我就是不明白为什么会发生这种事……

有趣的是,如果执行render 'messages/expired',不使用partial:并重命名文件以删除下划线,因此它不再是部分,它可以工作:

19:56:04 web.1  |   ↳ app/controllers/messages_controller.rb:3:in `show'
19:56:04 web.1  |   Rendering layout layouts/application.html.erb
19:56:04 web.1  |   Rendering messages/expired.html.erb within layouts/application
19:56:04 web.1  |   Rendered messages/expired.html.erb within layouts/application (Duration: 0.1ms | Allocations: 141)
19:56:04 web.1  |   Rendered layouts/_nav.html.erb (Duration: 0.4ms | Allocations: 124)
19:56:04 web.1  |   Rendered layout layouts/application.html.erb (Duration: 2.6ms | Allocations: 2627)
19:56:04 web.1  | Completed 200 OK in 7ms (Views: 3.4ms | ActiveRecord: 2.1ms | Allocations: 5494)

大胆猜测:这与所有这些都发生在show上的事实有关,所以一些Rails的默认启动。

控制器中的render方法处理参数的方式与视图中的略有不同。

# NOTE: :body, :plain, :html, :inline, :partial
#       will render without a layout
#       unless :layout option is specified
#       https://github.com/rails/rails/blob/v7.0.3/actionview/lib/action_view/layouts.rb#L431
def show
# Without layout
render partial: "expired"           # renders "messages/_expired"
# With layout
render "expired"                    # renders "messages/expired"
render template: "messages/expired" # renders "messages/expired"
render "_expired"                   # renders "messages/_expired"
# Doesn't work
render partial: "expired",          # renders "messages/_expired"
layout: "application"             # in "layouts/_application" # <= doesn't exist
end

在视图中:

# Without layout
<%= render "expired" %>                      # renders "messages/_expired"
<%= render partial: "expired" %>             # renders "messages/_expired"
<%= render template: "messages/_expired" %>  # renders "messages/_expired"
<%= render template: "messages/expired" %>   # renders "messages/expired"

# With layout
<%= render template: "messages/expired", layout: "layouts/application" %>
# renders "messages/expired"
# in "application" layout (again)
<%= render partial: "expired", layout: "application" %>
# renders "messages/_expired"
# in "messages/_application" partial layout

您可以保留_expired部分或将其重命名为expired并使用适当的渲染调用。


https://api.rubyonrails.org/classes/AbstractController/Rendering.html method-i-render

https://api.rubyonrails.org/classes/ActionView/Helpers/RenderingHelper.html method-i-render

最新更新