Nil and Presence in Ruby on Rails
By Randall Reed
One of the things I love about Ruby is nil. It can represent nothing and, since every expression in Ruby has a return value, nil is also a useful proxy for certain behavior.
For example, nil can represent that a variable was never assigned a value, or that a method never executed any statements.
def method_that_might_do_something(some_condition) if some_condition // do some stuff return true end end
When an if statement’s condition is fulfilled, that if statement returns the return value of the last expression evaluated inside the block. However, if the condition fails, the if statement returns nil.
So if we want to determine whether method_that_might_do_somethingexecuted any statements, we can just use something like:
foo = method_that_might_do_something if foo # do something else dependent on foo end
This also comes in useful if you have a variable that is assigned a value under certain execution paths and you want to provide a default otherwise. Since nil is falsey, it can be combined with a more meaningful result via the OR operator (||).
return some_string || some_default_string
A Wrinkle in Nil
But what if some_string will be an empty string (‘’) instead of nil? We have a problem…
# irb > ‘’ || ‘default’ => ""
An empty string is truthy in Ruby, so in this case, the code above would return “”. If you still wanted to preserve the same default string functionality, you would need to add some additional logic.
Presence to the Resuce
When I encountered this behavior recently in a Rails project, my first thought was to utilize a ternary operator, which was okkkk…
some_string.present? some_string : some_default_string
But looking at that code, my rails-sense started tingling.
Repeating some_string was redundant, and I had a hunch Rails had implemented a better way to handle this circumstance. And indeed it had — presence!
some_string.presence || some_default_string
A cousin of present?, presence returns the object if present? would evaluate to true, and nil otherwise.
# rails console > ''.present? => false > ''.presence => nil > 'default'.present? => true > 'default'.presence => "default"
Plugging this in allows us to use our original code with only a minor variation, and now it handles both nil and empty string perfectly! Delightful.
Note: Due to it’s relation to present?, presence is only available in Rails, not in vanilla Ruby.