我一直是个坏孩子,在我的局部模板中使用以下语法来设置局部变量的默认值,如果一个值没有显式地定义在:locals散列中,当呈现局部——时

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

这似乎工作得很好,直到最近(不知道为什么我能看出),未传递的变量开始表现得好像它们被定义为nil(而不是未定义)。

正如SO上许多乐于助人的人指出的那样,http://api.rubyonrails.org/classes/ActionView/Base.html说不要使用

defined? foo

而是使用

local_assigns.has_key? :foo

我正试图改变我的方式,但这意味着要改变很多模板。

我可以/应该直接在所有模板中进行这种更改吗?有什么诡计需要我注意吗?我需要多努力地测试每一个?


当前回答

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

<% 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] %>

其他回答

如果你不想每次调用局部变量时都传递局部变量给分部,你可以这样做:

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

这样可以避免未定义的变量错误。这将允许您调用带有/不带有局部变量的分部。

由于local_assign是一个哈希值,您还可以将fetch与可选的default_value一起使用。

local_assigns.fetch :foo, default_value

如果foo没有设置,它将返回default_value。

警告:

小心使用local_assignments。当default_value是一个方法时,它将被调用,以便将其结果传递给Fetch。

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

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

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

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

使用定义的?标题不起作用。这是一个实现限制。

Ruby 2.5

Erb

这是可能的,但必须在作用域中声明默认值。

变量替换词。

# 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 %>
...

更直观、紧凑:

<% some_local = default_value除非local_assign [:some_local] %>