Check emptiness in Ruby, nil? vs blank? vs empty? vs presence?
“if” alone may not be enough
if false
or if nil
won’t execute the corresponding condition, because false
and nil
are considered as falsy values.
In other words, if you cast nil
or false
as a boolean, it will return false
. Every other kind of value is considered truthy in Ruby. A quick hack (not only specific to Ruby, it also works with JavaScript) is to prepend a double exclamation mark before the variable.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
!!nil # nil => false
!!false # boolean false => false
!!true # boolean true => true
!!0 # number zero => true
!!42 # number other than zero => true
!!"" # empty string => true
!!" " # spaces-only string => true
!!"sth" # non-empty string => true
!![] # empty array => true
!![nil] # array with empty values => true
!!['a', 'z'] # non-empty array => true
!!{} # empty hash => true
!!{a: nil} # hash with empty values => true
!!{a: 42} # non-empty hash => true
!!/regex/ # regex => true
!!Time.now # any object => true
.nil? is from Ruby, check if object is actually nil
That’s the easy part. In Ruby, you can check if an object is nil, just by calling the nil? on the object… even if the object is nil. That’s quite logical if you think about it :)
Side note : in Ruby, by convention, every method that ends with a question mark is designed to return a boolean (true or false). In JavaScript, the convention is different : often, this kind of method starts with “is” (isEmpty, isNumeric, etc).
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
nil.nil? # nil => true
false.nil? # boolean false => false
true.nil? # boolean true => false
0.nil? # number zero => false
42.nil? # number other than zero => false
"".nil? # empty string => false
" ".nil? # spaces-only string => false
"sth".nil? # non-empty string => false
[].nil? # empty array => false
[nil].nil? # array with empty values => false
['a', 'z'].nil? # non-empty array => false
{}.nil? # empty hash => false
{a: nil}.nil? # hash with empty values => false
{a: 42}.nil? # non-empty hash => false
/regex/.nil? # regex => false
Time.now.nil? # any object => false
.empty? is from Ruby, it checks if size is 0
.empty?
is a Ruby method, which works only for Hash, Array, or String. But not for every Enumerable. It returns true if size is above zero. For others it returns a NoMethodError.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
nil.empty? # nil => NoMethodError
false.empty? # boolean false => NoMethodError
true.empty? # boolean true => NoMethodError
0.empty? # number zero => NoMethodError
42.empty? # number other than zero => NoMethodError
"".empty? # empty string => true
" ".empty? # spaces-only string => false
"sth".empty? # non-empty string => false
[].empty? # empty array => true
[nil].empty? # array with empty values => false
['a', 'z'].empty? # non-empty array => false
{}.empty? # empty hash => true
{a: nil}.empty? # hash with empty values => false
{a: 42}.empty? # non-empty hash => false
/regex/.empty? # regex => NoMethodError
Time.now.empty? # custom object => NoMethodError
.blank? is from ActiveSupport
.blank?
Comes from wonderful ActiveSupport. ActiveSupport is a dependency of Rails, so if you are inside the Rails environment, you already have this method, for free.
The NoMethodError
above could be annoying. So ActiveSupport adds a .blank? method that never fails.
Warning : what is considered as “blank” for Rails is opinionated. String with whitespace is considered “blank”, but not the number “0”. See the list here :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
nil.blank? # nil => true
false.blank? # boolean false => true
true.blank? # boolean true => false
0.blank? # number zero => false
42.blank? # number other than zero => false
"".blank? # empty string => true
" ".blank? # spaces-only string => true
"sth".blank? # non-empty string => false
[].blank? # empty array => true
[nil].blank? # array with empty values => false
['a', 'z'].blank? # non-empty array => false
{}.blank? # empty hash => true
{a: nil}.blank? # hash with empty values => false
{a: 42}.blank? # non-empty hash => false
/regex/.blank? # regex => false
Time.now.blank? # custom object => false
No more errors… but opinionated ways to define what is “blank” or not. So pay extra attention :
0.blank?
returns false. In my humble opinion, 0 should have been considered as a “blank” value. It would have been more consistent with other languages.false.blank?
returns true. Could be seen as weird or logical, depending on your habits.[nil, ''].blank?
returns false. An array of blank values is not considered as blank. This time, I find it logical because the method blank evaluates the array, not what’s inside the array.- Now the tricky part :
[nil].any?
returns false. But[''].any?
returns true. It’s because the empty string is truthy. If you want to check that[nil, '']
doesn’t contain anything interesting, you can do it this way :[nil, ''].all?(&:blank?)
returns true.
.present? is also from ActiveSupport
.present? is the negation of blank, so no surprise here :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
nil.present? # nil => false
false.present? # boolean false => false
true.present? # boolean true => true
0.present? # number zero => true
42.present? # number other than zero => true
"".present? # empty string => false
" ".present? # spaces-only string => false
"sth".present? # non-empty string => false
[].present? # empty array => false
[nil].present? # array with empty values => true
['a', 'z'].present? # non-empty array => true
{}.present? # empty hash => false
{a: nil}.present? # hash with empty values => true
{a: 42}.present? # non-empty hash => true
/regex/.present? # regex => true
Time.now.present? # custom object => true
Conclusion
As a memo, I put here this decision table, freely inspired by this article.
Method | if () | nil? | empty? | any? | blank? | present?(!blank?) |
Scope | ruby | rails only | ||||
Object | all | String, Array, Hash | Enumerable | all | ||
nil | false | true | NoMethodError | NoMethodError | true | false |
false | false | false | NoMethodError | NoMethodError | true | false |
true | true | false | NoMethodError | NoMethodError | false | true |
0 | true | false | NoMethodError | NoMethodError | false | true |
42 | true | false | NoMethodError | NoMethodError | false | true |
"" | true | false | true | NoMethodError | true | false |
" " | true | false | false | NoMethodError | true | false |
"sth" | true | false | false | NoMethodError | false | true |
[] | true | false | true | false | true | false |
[nil] | true | false | false | false | false | true |
['a', 'z'] | true | false | false | true | false | true |
{} | true | false | true | false | true | false |
{ a: nil } | true | false | false | true | false | true |
{ a: 42 } | true | false | false | true | false | true |
/regex/ | true | false | NoMethodError | NoMethodError | false | true |
Time.now | true | false | NoMethodError | NoMethodError | false | true |