Avoiding nil in Ruby programs (and NULL in databases)
Most Ruby developers see the following exception in production, no matter how well taken care their codebase is:
1
NoMethodError: undefined method `name' for nil:NilClass
And the search begins. Was it a user? Or another object that would respond to
#name
if present? Was it a typo? Many different statements can return nil
:
1
2
3
4
5
6
session[:blog_pozt] # => nil
session[:current_user] # => nil
@currentz_uzer # => nil
array[length + 1] # => nil
if false then 1 end # => nil
empty_method() # => nil
Our preference is to return anything but nil. A quick improvement is to
return a symbol! Authentication Ruby gems return nil
on current_user
by
default, but we can do better:
1
2
3
4
5
6
def current_user
super || :guest_user
end
# Now the error would read:
NoMethodError: undefined method `name' for :guest_user:Symbol
A symbol shows the source of the problem within the (otherwise generic) error message.
See also Rails Refactoring Example: Introduce Null Object.
NOT NULL
database constraints, or Rails validations?
Both! Our preference is to add a null: false
constraint to any new column in
migrations that store required values. The Rails presence validation ensures
forms and error messages work as intended, while the DB constraint will ensure
that no console session, bug, factory, ourselves when sleepy, or any connection
to our DB store invalid data.
Even when the field is not required, a constraint with a default value is
better than allowing nil (null: false, default: ""
). That way we ensure we
always deal with instances of String
and not also of NilClass
, avoiding type
checks and potential bugs.
See also If You Gaze Into nil, nil Gazes Also Into You.
Enjoy!