Image
#ruby
Posted March 30, 2021 ‐  8 min read

Ruby : nil? vs blank? vs empty? vs present?

The problem

More often than not, you have to check if an object is empty. But what does "empty" means exactly ?

"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.

!!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).

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.

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 :

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 :

.present? is also from ActiveSupport

.present? is the negation of blank, so no surprise here :

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 (or activeSupport) 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

Help needed 😊

If you enjoyed the article, you can :

  • Share the article on Twitter , or LinkedIn , or Reddit , it will stimulate the writing effort, thanks !
  • Subscribe to the newsletter, you'll be warned each time a new Rails tutorial is released : we start from the rails new command to fully understand a new concept.
  • Subscribe to the Bootrails Beta, it's a tool to launch new Rails apps.

Thanks to all,

David