了解 Rails 在渲染部分(并将局部变量传递给它们)方面的“魔力”。
为什么这样做:
<%= render "rabbits/form" %>
这项工作:
<%= render "rabbits/form", :parent => @warren, :flash => flash %>
但这确实不工作:
<%= render "rabbits/form", :locals => { :parent => @warren, :flash => flash } %>
但是这样做:
<%= render :partial =>"rabbits/form", :locals => { :parent => @warren, :flash => flash } %>
另外,我怎样才能查看这些细微差别,这样我就不需要打扰 S.O. 上的人了?
简短的回答是 render 方法会查看您传入的第一个参数。如果您传入一个散列(包括
:partial => 'foo', :locals => {blah blah blah}
),那么它会将您的所有参数作为散列传入并相应地解析它们。
如果你传入一个字符串作为你的第一个参数,它假定第一个参数是你的部分名称,并将其余部分作为你的本地人传递。然而,在随后的调用中,它实际上分配了
:locals => your_locals_argument
,在这种情况下是整个:locals => {locals hash}
,而不仅仅是{locals hash}
;即你最终得到:locals => {:locals => {locals hash}}
,而不是:locals => {locals hash}
.
所以我的建议是始终以相同的方式显式传递值,这样就不会有问题。为了了解这一点,我直接转到代码本身(actionpack/lib/base.rb,
render()
Rails 2 中的方法;Rails 3 不同)。这是一个很好的锻炼。
此外,不要担心“打扰” SO 上的人。这就是这个网站存在的原因。我什至从中学到了一些东西。
如果需要指定:locals,需要指定:partial或:template
<%= render :partial => "rabbits/form", :locals => {...} %>
应该工作
老实说,我只知道这些用例,因为过去几年我一直在跟上 Rails 的步伐,并阅读了有关添加新方法的公告。我自己也经常犯错,但通常很容易改正。
如果你问我,这是 Rails API 中尚未彻底考虑的部分之一。多年来它只是积累了越来越多的语法糖,而没有贬低任何旧行为。渲染方法有糖尿病。
更糟糕的是,渲染在控制器和视图中的行为不同。我还会查看第一个参数的内容,看它是文件、模板、操作还是部分。如果它以斜杠开头,那么它就是一个文件,或者类似的东西。
我赞成尽可能使用更短的符号。因为简短的符号确实很好地传达了意图。阅读它时,它通常会按照您的想法行事。编写部分内容并不简单。
这里是渲染方法的来源http://api.rubyonrails.org/classes/ActionView/Rendering.html#method-i-render:
def render(options = {}, locals = {}, &block)
case options
# Here is your last case
when Hash
if block_given?
_render_partial(options.merge(:partial => options.delete(:layout)), &block)
elsif options.key?(:partial)
_render_partial(options)
else
template = _determine_template(options)
lookup_context.freeze_formats(template.formats, true)
_render_template(template, options[:layout], options)
end
when :update
update_page(&block)
else
# here the first three cases
_render_partial(:partial => options, :locals => locals)
end
end
希望这有帮助!
我在 rails 7 / ruby 3.2.1 中遇到了一点麻烦,所以为了彻底起见:
# Works:
<%= render partial: 'publish_unpublish_button', locals: { something: 2, more: 5 } %>
# Works:
<%= render 'publish_unpublish_button', something: 2, more: 5 %>
# Won't work
<%= render 'publish_unpublish_button', locals: { something: 2, more: 5 } %>