DEV Community

loading...
Cover image for Ruby : nil? vs blank? vs empty? vs present?

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

bdavidxyz profile image David Boureau Originally published at bootrails.com ・6 min read

Article originally published here : https://bootrails.com/blog/ruby-nil-vs-blank-vs-empty-vs-presence

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  
Enter fullscreen mode Exit fullscreen mode

.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  
Enter fullscreen mode Exit fullscreen mode

.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  
Enter fullscreen mode Exit fullscreen mode

.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  
Enter fullscreen mode Exit fullscreen mode

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 :

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  
Enter fullscreen mode Exit fullscreen mode

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

Discussion (0)

pic
Editor guide