rails 部分模板中的可选局部变量:我如何摆脱(定义的?foo)混乱?
Posted
技术标签:
【中文标题】rails 部分模板中的可选局部变量:我如何摆脱(定义的?foo)混乱?【英文标题】:optional local variables in rails partial templates: how do I get out of the (defined? foo) mess? 【发布时间】:2011-01-04 20:34:29 【问题描述】:如果渲染部分时没有在 :locals 哈希中明确定义值,我在部分模板中使用以下语法为局部变量设置默认值 --
<% foo = default_value unless (defined? foo) %>
直到最近,这似乎工作得很好,当时(我无法辨别)未传递的变量开始表现得好像它们已被定义为 nil(而不是未定义)。
正如各种乐于助人的人在 SO 上指出的那样,http://api.rubyonrails.org/classes/ActionView/Base.html 说 不 使用
defined? foo
改为使用
local_assigns.has_key? :foo
我正在尝试修改我的方式,但这意味着要更改很多模板。
我可以/是否应该提前收费并在所有模板中进行此更改?我需要注意什么技巧吗?我需要多努力地测试每一项?
【问题讨论】:
这个问题已经很老了,所有的答案似乎都已经过时了,因为现在的Action View documentation,特别说可以用definded? foo
:"另外,你也可以用defined ? 使用前先检查变量是否已赋值的标题。”
【参考方案1】:
怎么样
<% foo ||= default_value %>
这表示“如果 foo
不是 nil 或 true,则使用它。否则将 default_value
分配给 foo”
【讨论】:
我不确定这是否有效,因为 foo 没有定义,除非它通过本地哈希传递。 这行得通,但如果你有这样的默认值,也许这表明你应该使用帮助器? 这里没有魔法。有关该主题的更多资源:groups.google.com/group/comp.lang.ruby/browse_thread/thread/… 我真的很喜欢这个版本,因为它的语法非常紧凑。我想最大的缺点是这意味着您不能将 nil 或 false 作为本地值传递,因为它将被默认覆盖。 @brahn,这是一个很好的观点。事实上,如果foo
是布尔值,则应该避免这种情况。它可能正确地具有false
的值,并被default_value
意外覆盖。【参考方案2】:
我这样做:
<% some_local = default_value if local_assigns[:some_local].nil? %>
【讨论】:
虽然我真的很喜欢 hgimenez 建议的简洁语法(上图),但这种方法的优点是非常清楚:发生了什么。 (仍然有不让您将 nil 作为本地值传递的缺点) 你想要传递 nil 的用例是什么? 哦,我没有具体的案例。只是试图了解全部含义。这提醒我接受这个答案:-) 为了解决 nil 问题,我从 OP 的链接 (api.rubyonrails.org/classes/ActionView/Base.html) 标题: -- has_key 避免了 nil / false 的情况,并且可能可以像这里的答案一样缩短为一行 请检查 Pablo 的回答:local_assigns.fetch
完美处理具有 nil 值的键。仅当密钥未完全设置时,它才会返回默认值。【参考方案3】:
可以创建如下所示的助手:
somearg = opt(:somearg) :defaultvalue
实现如下:
module OptHelper
def opt(name, &block)
was_assigned, value = eval(
"[ local_assigns.has_key?(:#name), local_assigns[:#name] ]",
block.binding)
if was_assigned
value
else
yield
end
end
end
请参阅my blog,了解有关如何以及为什么的详细信息。
请注意,此解决方案确实允许您将 nil 或 false 作为值传递而不会被覆盖。
【讨论】:
【参考方案4】:更直观、更紧凑:
<% some_local = default_value unless local_assigns[:some_local] %>
【讨论】:
我认为如果你用:locals => :some_local => false
调用部分,这将失败【参考方案5】:
我认为允许多个默认变量的更好选择:
<% options = local_assigns.reverse_merge(:include_css => true, :include_js => true) %>
<%= include_stylesheets :national_header_css if options[:include_css] %>
<%= include_javascripts :national_header_js if options[:include_js] %>
【讨论】:
【参考方案6】:我认为这应该在这里重复(来自http://api.rubyonrails.org/classes/ActionView/Base.html):
如果您需要在特定的渲染调用中找出某个局部变量是否已被赋值,您需要使用以下模式:
<% if local_assigns.has_key? :headline %>
Headline: <%= headline %>
<% end %>
使用定义的测试?标题行不通。这是一个实施限制。
【讨论】:
【参考方案7】:由于local_assigns
是一个哈希,您也可以将fetch 与可选的default_value
一起使用。
local_assigns.fetch :foo, default_value
如果未设置 foo
,这将返回 default_value
。
警告:
当default_value
是一种方法时,请注意local_assigns.fetch :foo, default_value
,因为无论如何都会调用它以将其结果传递给fetch
。
如果您的default_value
是一个方法,您可以将它包装在一个块中:local_assigns.fetch(:foo) default_value
以防止在不需要时调用它。
【讨论】:
值得明确地说:nil
值被保留在这里。如果哈希包含映射到nil
的:foo
,那么fetch
将返回nil
。也就是说,至少在我的 v1.9.3 上。我不记得 1.8 的表现如何。
完全正确。它让我想起了 local_assigns[:foo] || default_value
的问题,当 foo 返回一个虚假值时,将使用 default_value
代替。对于Memoization@some_value ||= expensive_method
来说通常是一个问题,如果该方法返回一个假值,它总是会被执行。
任何不明白为什么这是最佳答案的人都没有使用 ruby 足够长的时间。布拉沃巴勃罗!
以下是优化,因此您只需在模板顶部调用一次,而不是在每次使用变量时都使用“获取保护”。 foo ||= local_assigns[:foo] = local_assigns.fetch(:foo, default_value)
我想知道为什么它不起作用,我认为它也创建了变量,但我们仍然必须使用返回值:foo = local_assigns.fetch :foo, true
【参考方案8】:
如果您不想在每次调用时都将局部变量传递给局部变量,请执行以下操作:
<% local_param = defined?(local_param) ? local_param : nil %>
这样可以避免undefined variable
错误。这将允许您调用带/不带局部变量的局部变量。
【讨论】:
OR local_param = local_param if defined?(local_param)【参考方案9】:这是 Pablo 答案的派生词。这允许我设置一个默认值('full'),最后,在 local_assigns 和一个实际的局部变量中都设置了 'mode'。
haml/苗条:
- mode ||= local_assigns[:mode] = local_assigns.fetch(:mode, 'full')
erb:
<% mode ||= local_assigns[:mode] = local_assigns.fetch(:mode, 'full') %>
【讨论】:
【参考方案10】:我知道这是一个旧线程,但这是我的小贡献:我会在部分内部的 条件 中使用local_assigns[:foo].presence
。
然后我只在渲染调用中需要时设置foo
:
<%= render 'path/to/my_partial', always_present_local_var: "bar", foo: "baz" %>
看看official Rails guide here。从 RoR 3.1.0 开始有效。
【讨论】:
我看不出local_assigns[:foo]
和local_assigns[:foo].presence
之间有什么真正的区别。如果哈希中不存在键,则任何一个都将返回nil
,如果存在则返回值。【参考方案11】:
就我而言,我使用:
<% variable ||= "" %>
在我的部分。 我不知道这是否好,但对我来说还可以
【讨论】:
这实际上效果很好。适用于未定义以及在部分调用中将nil
作为本地传递时。
啊,往下看,如果variable
是一个布尔值并且你需要将它设置为false
,这将失败。它将使用默认值而不是使用false
值。使用风险自负。
这是最干净的方法,没有真正的混淆。【参考方案12】:
红宝石 2.5
Erb
这是可能的,但你必须在范围内声明你的默认值。
VARIABLE 替换词。
# index.html.erb
...
<%= render 'some_content', VARIABLE: false %>
...
# _some_content.html.erb
...
<% VARIABLE = true if local_assigns[:VARIABLE].nil? %>
<% if VARIABLE %>
<h1>Do you see me?</h1>
<% end %>
...
【讨论】:
以上是关于rails 部分模板中的可选局部变量:我如何摆脱(定义的?foo)混乱?的主要内容,如果未能解决你的问题,请参考以下文章
Rails 3:“未定义的局部变量或方法”如果我将内容放在部分中