243

I've been a bad kid and used the following syntax in my partial templates to set default values for local variables if a value wasn't explicitly defined in the :locals hash when rendering the partial --

<% foo = default_value unless (defined? foo) %>

This seemed to work fine until recently, when (for no reason I could discern) non-passed variables started behaving as if they had been defined to nil (rather than undefined).

As has been pointed by various helpful people on SO, http://api.rubyonrails.org/classes/ActionView/Base.html says not to use

defined? foo

and instead to use

local_assigns.has_key? :foo

I'm trying to amend my ways, but that means changing a lot of templates.

Can/should I just charge ahead and make this change in all the templates? Is there any trickiness I need to watch for? How diligently do I need to test each one?

4

12 回答 12

351

我这样做:

<% some_local = default_value if local_assigns[:some_local].nil? %>
于 2010-01-13T23:12:48.233 回答
171

由于local_assigns是哈希,您还可以将fetch与可选的default_value.

local_assigns.fetch :foo, default_value

default_value如果foo未设置,这将返回。

警告:

小心local_assigns.fetch :foo, default_valuewhendefault_value是一个方法,因为无论如何都会调用它以将其结果传递给fetch.

如果你default_value是一个方法,你可以将它包装在一个块中:local_assigns.fetch(:foo) { default_value }以防止它在不需要时被调用。

于 2013-06-27T11:46:56.913 回答
88

怎么样

<% foo ||= default_value %>

这表示“foo如果它不是 nil 或 true 则使用。否则分配default_value给 foo”

于 2010-01-13T22:35:17.857 回答
13

我认为这应该在这里重复(来自http://api.rubyonrails.org/classes/ActionView/Base.html):

如果您需要找出某个局部变量是否在特定的渲染调用中被赋值,您需要使用以下模式:

<% if local_assigns.has_key? :headline %>
  Headline: <%= headline %>
<% end %>

使用定义的测试?标题行不通。这是一个实施限制。

于 2013-03-26T07:33:51.597 回答
10

就我而言,我使用:

<% variable ||= "" %>

在我的部分。
我不知道这是否好,但对我来说还可以

于 2015-05-28T22:50:59.280 回答
5

我知道这是一个旧线程,但这是我的小贡献:我将local_assigns[:foo].presence在部分内部的条件中使用。然后我foo只在渲染调用中需要时设置:

<%= render 'path/to/my_partial', always_present_local_var: "bar", foo: "baz" %>

在这里查看官方 Rails 指南。从 RoR 3.1.0 开始有效。

于 2014-08-28T22:04:56.893 回答
2

这是巴勃罗答案的派生词。这允许我设置一个默认值('full'),最后,在 local_assigns 和一个实际的局部变量中都设置了'mode'。

哈姆/苗条:

- mode ||= local_assigns[:mode] = local_assigns.fetch(:mode, 'full')

erb:

<% mode ||= local_assigns[:mode] = local_assigns.fetch(:mode, 'full') %>
于 2014-08-13T15:59:03.317 回答
1

我认为允许多个默认变量的更好选择:

<% 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] %>
于 2012-03-13T03:39:44.950 回答
1

红宝石 2.5

厄伯

这是可能的,但您必须在范围内声明您的默认值。

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 %>
...
于 2018-08-12T15:52:24.797 回答
0

更直观、更紧凑:

<% some_local = default_value unless local_assigns[:some_local] %>

于 2011-11-16T20:07:34.853 回答
0

If you do not want to pass local variable to partial each time you call it you do this:

<% local_param = defined?(local_param) ? local_param : nil %>

This way you avoid undefined variable error. This will allow you to call your partial with/without local variables.

于 2013-11-18T15:25:10.153 回答
-6

可以创建一个助手,如下所示:

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

有关如何以及为什么的详细信息,请参阅我的博客

请注意,此解决方案确实允许您将 nil 或 false 作为值传递而不会被覆盖。

于 2010-03-30T02:01:38.380 回答