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:
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:
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:
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:
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:
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:
or the Smalltalk-ish:
or even (gasp!):
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!