bootrails.com is now moving to saaslit.com  See you there!
bootrails moves to  saaslit.com
Post

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.

Methodif ()nil?empty?any?blank?present?(!blank?)
Scoperubyrails only
ObjectallString, Array, HashEnumerableall
nilfalsetrueNoMethodErrorNoMethodErrortruefalse
falsefalsefalseNoMethodErrorNoMethodErrortruefalse
truetruefalseNoMethodErrorNoMethodErrorfalsetrue
0truefalseNoMethodErrorNoMethodErrorfalsetrue
42truefalseNoMethodErrorNoMethodErrorfalsetrue
""truefalsetrueNoMethodErrortruefalse
" "truefalsefalseNoMethodErrortruefalse
"sth"truefalsefalseNoMethodErrorfalsetrue
[]truefalsetruefalsetruefalse
[nil]truefalsefalsefalsefalsetrue
['a', 'z']truefalsefalsetruefalsetrue
{}truefalsetruefalsetruefalse
{ a: nil }truefalsefalsetruefalsetrue
{ a: 42 }truefalsefalsetruefalsetrue
/regex/truefalseNoMethodErrorNoMethodErrorfalsetrue
Time.nowtruefalseNoMethodErrorNoMethodErrorfalsetrue
This post is licensed under CC BY 4.0 by the author.