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.