我有一个动作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