【问题标题】:Ruby iterate over a variable unless it is nilRuby 遍历一个变量,除非它是 nil
【发布时间】:2015-08-18 16:58:29
【问题描述】:

我希望 .html.erb 中的一种干净方式仅在变量不为 nil 时循环遍历变量。

如果@family 为nil,我希望执行以下操作。

<% @family.children.each.with_index(1) do |family_member, index| %>
    // HTML HERE
<% end %>

我试图避免做这样的事情

<% if @family %>
   <% @family.children.each.with_index(1) do |family_member, index| %>
       // HTML HERE
   <% end %>
<% end %>

尤其是尽量避免需要

<% if @family && @family.children %>
      <% @family.children.each.with_index(1) do |family_member, index| %>
          // HTML HERE
      <% end %>
<% end %>

有没有更好的方法来做到这一点?

【问题讨论】:

  • @family &amp;&amp; @family.children &amp;&amp; @family.children.each.with_index(1)... 怎么样?
  • 你可以试试这个&lt;% @family.try(:children).each.with_index(1) do |family_member, index| %&gt; 吗?
  • @Pavan:这将导致未定义的方法 each 用于 nil:NilClass
  • 包含您尝试迭代的集合的对象似乎是 nil,而不是集合本身。
  • 我正在努力防止两者都是 nil。

标签: ruby-on-rails ruby ruby-on-rails-4 erb


【解决方案1】:

此解决方案可能会产生误导,但 Ruby 的语法允许您这样做:

<% @family.children.each.with_index(1) do |family_member, index| %>
    // HTML HERE
<% end unless @family.blank? %>
#      ^^^^^^^^^^^^^^^^^^^^^

我只将此解决方案用于简单的语句,例如测试对象的存在(如您的情况)。 对于更复杂的逻辑,我不推荐这种解决方案,因为第三方不会知道条件在块的末尾。


另一个:

<% (@family.try(:children) || []).each.with_index(1) do |family_member, index| %>

# mu-is-too-short's (brilliant) suggestion:
<% @family.try(:children).to_a.each.with_index(1) do |family_member, index| %>

如果@familyniltry(:children) 不会引发错误,但会返回nil,然后nil || [] 返回空数组“你可以循环它”(循环它为零次)。

【讨论】:

  • 我想知道为什么我的建议返回undefined method each for nil:NilClass。您的解释消除了我的疑问。谢谢:)
  • 这是干净简洁的,但不是人类可读的。对于进来查看您的代码的第三方,我不知道条件是在 HTML 块的 end 处。
  • 为什么不@family.try(:children).to_a
  • @muistooshort 因为我从来没想过!辉煌;)
  • 各种to_X方法是我通常忽略nils的方法。
【解决方案2】:

您可以使用Null Object,例如:

class NullFamily
  def children
    []
  end
end

在您的控制器中:

@family = some_finder || NullFamily.new

或者你可以传递一个单独的变量@children:

@family = some_finder
@children = @family.try(:children).to_a

并将循环更改为:

<% @children.each.with_index(1) do |family_member, index| %>
    // HTML HERE
<% end %>

【讨论】:

  • @Anthony 确实,很棒的演讲。我可以一遍又一遍地看它:-)
【解决方案3】:

这个怎么样:

<% @family && @family.children.each.with_index(1) do |family_member, index| %>
    // HTML HERE
<% end %>

【讨论】:

  • 你需要@family &amp;&amp; @family.children @family.children.each...
  • @CarySwoveland,大概如果@family 存在,它就有孩子。
  • @Sergio,我是通过 OP 的 if @family &amp;&amp; @family.children 来的。据我所知,一对没有孩子的夫妇可能有@family.children #=&gt; nil 而不是@family.children #=&gt; [](尽管后者似乎更好的设计)。
  • @CarySwoveland,是的,我明白了。不知何故,我的印象是children 保证是非空的。我一定是错的。
  • 这也是一个很好的解决方案
【解决方案4】:

也许您可以在控制器中使用它?

@family ||= []

【讨论】:

  • [] 不回复children
【解决方案5】:

如果@family.present 可以使用吗?或相反,除非@family.blank?

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-12-12
    • 2012-04-10
    • 2015-03-15
    • 1970-01-01
    • 1970-01-01
    • 2023-01-27
    相关资源
    最近更新 更多