MicFin
MicFin

Reputation: 2501

Ruby iterate over a variable unless it is nil

I would like a clean way in .html.erb to loop through a variable ONLY if the variable is not nil.

I would like the following to execute but not if @family is nil.

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

I am trying to avoid doing something like this

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

And especially trying to avoid needing

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

Is there a better way to do this?

Upvotes: 5

Views: 4807

Answers (5)

MrYoshiji
MrYoshiji

Reputation: 54882

This solution can be misleading but Ruby's syntax allows you to do so:

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

I only use this solution for simple statements like testing the presence of an object (like in your case). I do not recommend this solution for a more complex logic because a third party would not know that the condition is at the end of the block.


Another one:

<% (@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| %>

If @family is nil, the try(:children) won't raise an error but will return nil, then nil || [] returns the empty array which "you can loop on it" (loop on it zero times actually).

Upvotes: 6

Stefan
Stefan

Reputation: 114178

You could use a Null Object, something like:

class NullFamily
  def children
    []
  end
end

In your controller:

@family = some_finder || NullFamily.new

Or you could pass a separate variable @children:

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

And change your loop to:

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

Upvotes: 5

Nikola Todorovic
Nikola Todorovic

Reputation: 310

Maybe you can have this in your controller?

@family ||= []

Upvotes: 1

Md Sirajus Salayhin
Md Sirajus Salayhin

Reputation: 5144

You can use if @family.present? or the opposite as unless @family.blank?

Upvotes: 0

Doydle
Doydle

Reputation: 921

How about this:

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

Upvotes: 4

Related Questions