Have you encountered frustrating errors caused by nil
values in your code? A more reliable solution is to design your code to avoid them whenever possible. One of Ruby’s strengths is its ability to substitute meaningful objects where nil might otherwise appear, allowing for more predictable and resilient behaviour.
For example, imagine a page that lists all chat messages for the current user:
<%= render partial: "chats/summary", collection: Current.user.chats %>
This works well—until the user signs out. At that point, the page fails because Current.user
is nil
.
To prevent this, you can introduce a class that behaves like a User
but handles the scenario where no user is signed in:
class GuestUser
def user_name = "Guest"
def chats = Chat.none
# …
end
Using Chat.none
instead of []
ensures that the chats
relationship behaves like an ActiveRecord relation. This means you can chain methods on it without introducing errors.
Implementing this approach often requires a small adjustment to your authentication flow. For example, with Rails 8’s authentication generator, you can update the Current
class as follows:
# app/models/current.rb
class Current < ActiveSupport::CurrentAttributes
# Remove this line:
# delegate :user, to: :session, allow_nil: true
def user
session&.user || GuestUser.new
end
end
Rather than allowing nil
to propagate through your application, use an object like GuestUser
to represent the absence of a user. This pattern captures the concept of “nothing” in a more structured way and helps reduce unexpected errors.