How to check collection for items
There is a lot of similarities between ruby and C#. Unfortunately, there is a few subtle differences on places you wouldn’t expect them to be. And sometimes they can break your neck, or code.
One of them is how you check whether a collection is empty. In C# there is Any()
method that can take a predicate to match an item or can be called without it. When called without it returns false if the collection is empty.
if (Authorizations.any?)
{
DoSomething();
}
Ruby also contains any?
, but it behaves slightly differently. You can pass a predicate as in C# and it could be called without one as well.
do_something if authorizations.any?
You would expect do_something
to be called when authorizations contains any element, right? Not exactly.
authorizations = [false, false, false]
do_something if authorizations.any?
In the example above the method doesn’t get called. What the hell? We have an array with three booleans, so the array is not empty, but all of them are false. When you call any?
without a block (predicate) it appends an implicit one { |obj| obj}
and when all fields are false or nil it returns false.
What can we do to fix the code? It depends on the context, so let’s start with Rails associations. The best way to test association is to use exists?
method.
do_something if authorizations.exists?
If you are in Rails and you work with arrays or hashes instead of associations you are more likely to use present?
.
do_something if authorizations.present?
And if you are only in ruby, you are left behind with !
or using unless
instead.
do_something if !authorizations.empty?
do_something unless authorizations.empty?
Lesson for today is don’t call any?
without passing a block if you want to check just for element presence.