Ruby迭代变量,除非它是零

Mic*_*Fin 4 ruby ruby-on-rails erb ruby-on-rails-4

如果变量不是nil,我想在.html.erb中以干净的方式循环遍历变量.

我想要执行以下操作,但如果@family为零则不执行.

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

我试图避免做这样的事情

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

特别是试图避免需要

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

有一个更好的方法吗?

MrY*_*iji 5

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

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

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


另一个:

<% (@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| %>
Run Code Online (Sandbox Code Playgroud)

如果@familynil,try(:children)则不会引发错误但会返回nil,然后nil || []返回"你可以在其上循环"的空数组(实际上循环为零次).

  • 这是简洁明了的,但不是人类可读的.对于进入查看代码的第三方,我不知道条件是在HTML块的**结尾**. (2认同)

Ste*_*fan 5

您可以使用Null对象,例如:

class NullFamily
  def children
    []
  end
end
Run Code Online (Sandbox Code Playgroud)

在你的控制器中:

@family = some_finder || NullFamily.new
Run Code Online (Sandbox Code Playgroud)

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

@family = some_finder
@children = @family.try(:children).to_a
Run Code Online (Sandbox Code Playgroud)

并将您的循环更改为:

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