DEV Community

Cover image for Differences Between #nil?, #empty?, #blank?, and #present?
Joyce Echessa for AppSignal

Posted on • Originally published at blog.appsignal.com

Differences Between #nil?, #empty?, #blank?, and #present?

Ruby and Rails have several methods that can be used to check for the existence of a value or the state of an object. Ruby provides #nil? and #empty?, and Rails' ActiveSupport adds #blank? and #present?. All these work in their own way and it's important to know how each evaluates data as using the wrong method in your code might cause unexpected results.

In this article, we'll refresh your knowledge on these methods. We'll (re)learn what conditions pass or fail when each is used as well as the type of objects each method can be used on. We'll even throw in a handy cheat sheet at the end!

#nil?

#nil? is a Ruby method on the Object class. Since all classes inherit from this class, #nil? can be used on any object. It returns true for nil (an instance of the class NilClass) and false for everything else.

nil.nil?
=> true

true.nil?
=> false

5.nil?
=> false

"".nil?
=> false

[].nil?
=> false
Enter fullscreen mode Exit fullscreen mode

#empty?

#empty? is a method that can be used on strings, arrays, hashes and sets. It returns true if the instance of the object has a length of zero.

When used on strings, it returns true for empty strings.

"".empty?
=> true
Enter fullscreen mode Exit fullscreen mode

Note that whitespace characters are characters and so using #empty? on a string containing only whitespace will return false. Because of this, it might not be the best method to use when validating text. If you are only using this method to validate user input, for instance, you might end up processing input that only contains whitespace.

" ".empty?
=> false

"\t\n".empty?
=> false
Enter fullscreen mode Exit fullscreen mode

For arrays, hashes and sets, it returns true if they have no elements.

[].empty?
=> true

{}.empty?
=> true

require 'set'
Set.new.empty?
=> true
Enter fullscreen mode Exit fullscreen mode

When #empty? is used on nil or any other class that doesn't have the method, a NoMethodError exception will be raised. So to use it in checking your data, you have to put in place more checks to ensure your program never crashes.

if !myVar.nil? && !myVar.empty?
  # make use of myVar
end
Enter fullscreen mode Exit fullscreen mode

A better method to use would be the Rails #blank? method, which we'll now look at.

#blank?

#blank? is a Rails method (in ActiveSupport). It operates on any object.

For strings, it will return true for empty strings as well as strings containing only whitespace characters.

"".blank?
=> true

" ".blank?
=> true

"\n\t".blank?
=> true
Enter fullscreen mode Exit fullscreen mode

For arrays, hashes and sets, it works just like #empty?, in that it returns true if they have no elements.

[].blank?
=> true

{}.blank?
=> true

Set.new.blank?
=> true

[nil].blank?
=> false

["", ""].blank?
=> false

person = {:firstName => "John", :lastName => "Doe"}
person.blank?
=> false
Enter fullscreen mode Exit fullscreen mode

It returns false for true and true for any falsey conditions (i.e. nil and false).

true.blank?
=> false

false.blank?
=> true

nil.blank?
=> true
Enter fullscreen mode Exit fullscreen mode

As you can see, it is better to use #blank? rather than #empty? in validating data as it won't cause NoMethodErrors when used on some objects since it is available for all objects. It also won't pass for strings that only contain whitespace.

#present?

#present? is also a Rails method. It does the opposite of what #blank? does.

!myVar.blank? == myVar.present?
=> true
Enter fullscreen mode Exit fullscreen mode

Here are some examples:

"".present?
=> false

" ".present?
=> false

[].present?
=> false

nil.present?
=> false

true.present?
=> true

false.present?
=> false

{}.present?
=> false

person = {:firstName => "John", :lastName => "Doe"}
person.present?
=> true

5.present?
=> true
Enter fullscreen mode Exit fullscreen mode

This is also a better method for validation than #empty? for the same reasons we covered for #blank?.

In Conclusion

Since the naming of these methods tends to confuse, here's a handy cheat sheet for you to bookmark.

#nil? #empty? #blank? #present?
5 false NoMethodError false true
"" false true true false
" " false false true false
"\t\n" false false true false
[] false true true false
["a"] false false false true
{} false true true false
{a: "b"} false false false true
Set.new false true true false
nil true NoMethodError true false
true false NoMethodError false true
false false NoMethodError true true

As with everything, the choice between #nil?, #empty?, #blank? and #present? depends on the situation. For checking if a user has a name to address them with, #present? could be a good fit, for example. However #blank? and #present return a boolean for all objects, which might hide bugs in the code by not raising an error when a value is of the wrong type.

We hope we refreshed your memory on checking values in Ruby. If you have any questions or comments, don’t hesitate to leave a comment.

This post is written by guest author Joyce Echessa. Joyce is a full stack developer.

Top comments (1)

Collapse
 
phallstrom profile image
Philip Hallstrom

One thing I find interesting in Rails is that in ActiveRecord, in addition to present?, there is exists? and any? and while they all return true or false they do very different things to your database. present? will fetch the entire record via SELECT *, exists? will SELECT 1 using the conditions provided and any? will SELECT COUNT(*) but won't return the count, just true or false. Depending on your data this can have a measurable impact on performance. Tables that have many columns and blobs of data will suffer with present?. Tables with millions of rows can suffer with any? as COUNT isn't always a cheap operation (in PostgreSQL at least). exists? is most efficient, but only if you don't subsequently use the record as that will require a second trip to the database to fetch it.

Consider:

> Golfer.where(id: 1).present?
  Golfer Load (0.4ms)  SELECT "golfers".* FROM "golfers" WHERE "golfers"."id" = $1  [["id", 1]]
=> true
> Golfer.where(id: 1).exists?
  Golfer Exists (0.5ms)  SELECT  1 AS one FROM "golfers" WHERE "golfers"."id" = $1 LIMIT $2  [["id", 1], ["LIMIT", 1]]
=> true
> Golfer.where(id: 1).any?
   (1.6ms)  SELECT COUNT(*) FROM "golfers" WHERE "golfers"."id" = $1  [["id", 1]]
=> true

Ironic that in this case the less efficient query is faster, but my data set is small (20 records).