Introduction
Ruby on Rails provides a blank? method on all objects, but in plain Ruby you often need to check whether a value is “empty” in a broad sense โ nil, an empty string, a whitespace-only string, an empty array, or false. This article shows how to implement and use a blank? helper effectively.
The Problem
Checking for “emptiness” in Ruby requires handling multiple cases:
value = nil
value = ""
value = " " # whitespace only
value = []
value = {}
value = false
A naive check like if value misses empty strings and whitespace. value.empty? raises NoMethodError on nil. You need something more robust.
A Simple blank? Implementation
class Client
# Returns true if all credential values are present (non-blank)
# @return [Boolean]
def credentials?
credentials.values.none? { |v| blank?(v) }
end
private
# Returns true if the value is nil, false, empty, or whitespace-only
# @param s [Object] any value
# @return [Boolean]
def blank?(s)
s.respond_to?(:empty?) ? s.empty? : !s
end
end
This works because:
nil.respond_to?(:empty?)โfalse, so!nilโtrue(nil is blank)false.respond_to?(:empty?)โfalse, so!falseโtrue(false is blank)"".respond_to?(:empty?)โtrue, so"".empty?โtrue(empty string is blank)"hello".respond_to?(:empty?)โtrue, so"hello".empty?โfalse(not blank)[].respond_to?(:empty?)โtrue, so[].empty?โtrue(empty array is blank)
Handling Whitespace-Only Strings
The simple version above treats " " as non-blank (it’s not empty). To also treat whitespace-only strings as blank:
def blank?(s)
if s.respond_to?(:strip)
s.strip.empty?
elsif s.respond_to?(:empty?)
s.empty?
else
!s
end
end
blank?(nil) # => true
blank?(false) # => true
blank?("") # => true
blank?(" ") # => true (whitespace only)
blank?("hello") # => false
blank?([]) # => true
blank?([1, 2]) # => false
blank?({}) # => true
blank?(0) # => false (0 is not blank โ unlike Rails)
Module Version for Reuse
Wrap it in a module so any class can use it:
module Blankable
# Returns true if value is nil, false, empty, or whitespace-only
def blank?(value)
case value
when NilClass, FalseClass
true
when String
value.strip.empty?
when Array, Hash
value.empty?
else
false
end
end
# Opposite of blank?
def present?(value)
!blank?(value)
end
end
class UserValidator
include Blankable
def validate(user)
errors = []
errors << "Name is required" if blank?(user[:name])
errors << "Email is required" if blank?(user[:email])
errors
end
end
validator = UserValidator.new
puts validator.validate({ name: "", email: "[email protected]" }).inspect
# => ["Name is required"]
puts validator.validate({ name: "Alice", email: "[email protected]" }).inspect
# => []
Rails’ blank? Method
If you’re using Rails (ActiveSupport), blank? is already defined on all objects:
nil.blank? # => true
false.blank? # => true
"".blank? # => true
" ".blank? # => true
[].blank? # => true
{}.blank? # => true
0.blank? # => false
"hello".blank? # => false
[1].blank? # => false
# present? is the opposite
"hello".present? # => true
nil.present? # => false
You can use ActiveSupport standalone without the full Rails stack:
require 'active_support/core_ext/object/blank'
Practical Usage Patterns
Validating Required Fields
def create_user(params)
required = [:name, :email, :password]
missing = required.select { |field| blank?(params[field]) }
unless missing.empty?
raise ArgumentError, "Missing required fields: #{missing.join(', ')}"
end
User.new(params)
end
Default Values with present?
def display_name(user)
# Use nickname if present, fall back to full name
if present?(user[:nickname])
user[:nickname]
else
"#{user[:first_name]} #{user[:last_name]}".strip
end
end
Filtering Blank Values from Collections
def clean_tags(tags)
tags.reject { |tag| blank?(tag) }.map(&:strip).uniq
end
clean_tags(["ruby", "", " ", "rails", nil, "ruby"])
# => ["ruby", "rails"]
Safe String Coercion
def to_s_or_nil(value)
str = value.to_s.strip
blank?(str) ? nil : str
end
to_s_or_nil(nil) # => nil
to_s_or_nil("") # => nil
to_s_or_nil(" ") # => nil
to_s_or_nil("hello") # => "hello"
Comparison: nil?, empty?, blank?
| Value | .nil? |
.empty? |
blank? |
|---|---|---|---|
nil |
true |
NoMethodError |
true |
false |
false |
NoMethodError |
true |
"" |
false |
true |
true |
" " |
false |
false |
true |
"hello" |
false |
false |
false |
[] |
false |
true |
true |
[1] |
false |
false |
false |
0 |
false |
NoMethodError |
false |
Comments