I love each, but I have a problem with it. What happens when you have an empty collection?

If you call [].each, nothing will happen and [] will be returned. Sometimes, that’s what you want. But more often, especially when you’re building UI, you’ll want to handle empty lists in a special way. For example, I usually want to show a different message when I don’t have any data.

But since [].each returns [], not nil, you’re stuck writing something like this:

app/views/users/index.html.erb
1
2
3
4
5
6
7
<% if @users.empty? -%>
  <p>You don't have any users. <%= link_to "Add one!", new_user_path %></p>
<% else -%>
  <% @users.each do |user| -%>
      <p><%= user.name %></p>
  <% end -%>
<% end -%>

That works, but it feels awkward. I’d rather say, “Do this thing to each item in this collection, unless there’s nothing in it, in which case do this other thing entirely.” I want something like each, with an “or else.”

Rendering Rails Collections

Inside your views, Rails can help. It’s great at rendering collections of things:

app/views/users/index.html.erb
1
<%= render @users %>
app/views/users/_user.html.erb
1
<p><%= user.name %></p>

When render is passed @users, it renders _user.html.erb once for each user inside @users. You can skip the each entirely.

As a bonus, if @users is empty, render returns nil, just like we want! So you can write this, and get the same output as the original version:

app/views/users/index.html.erb
1
<%= render(@users) || render('empty') %>
app/views/users/_user.html.erb
1
<p><%= user.name %></p>
app/views/users/_empty.html.erb
1
<p>You don't have any users. <%= link_to "Add one!", new_user_path %></p>

It’s a lot more direct, once you understand Rails’ conventions.

What about outside of a view?

If you follow Rails, render with a collection is a fast, powerful way to render collections of objects.

But sometimes you won’t want to deal with an extra partial to render each item. Or render won’t support your design. Or you won’t even be inside a view.

The best solution I’ve found so far is presence.

list.presence is the same as:

1
2
3
4
5
if list.present?
  list
else
  nil
end

That is, you’ll get the list back if it has anything in it, and nil if it’s empty.

With presence, you could write:

1
2
3
@users.each do |user|
  puts user.name
end.presence || puts("You don't have any users.")

This prints each name if there are users in @users, or You don't have any users otherwise.

Still, I could do without the presence. It feels like a hack, because it is one. If it was supported, something like this might be better:

1
2
3
@users.each do |user|
  puts user.name
end || puts("You don't have any users.")

or the Smalltalk-ish:

1
2
3
@users.each(if_empty: lambda { puts "You don't have any users." }) do |user|
  puts user.name
end

or even (gasp!):

1
2
3
4
5
for user in @users
  puts user.name
else
  puts "You don't have any users."
end

For now, though, I usually just go with presence or the basic if blank?; else each pattern.

Which do you think is better? How do you handle empty lists? Have you found a better way? If so, tell me about it!

Did you like this post? You should read these:

Finished another Rails tutorial and still don’t know how to start?

Have you slogged through the same guide three times and still can't retain enough to write apps on your own?

In my free 7-part course, you’ll discover the fastest way to learn and remember new Rails ideas, so you can use them when you need them. And you'll learn to use what you already know to build your own Rails project.



Comments