Jonathan Bennett

Tame Your Nils

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.