Here is a small Ruby ENV variable gotcha I encountered and how I fixed it.
I had an environment variable controlling a feature flag:
if ENV['DISABLE_THING']
# skip the thing
end
Set DISABLE_THING=false, reloaded the app, and… the thing was still disabled. Which made no sense. I checked the value, I double-checked the spelling, I restarted the server. Same behavior.
The problem is obvious in retrospect. Environment variables are strings. ENV['DISABLE_THING'] returns "false". And in Ruby, "false" is truthy. It’s a non-empty string, so if ENV['DISABLE_THING'] always passes. The actual value doesn’t matter as long as it’s not empty or nil.
I fixed it with three lines at the top of config/application.rb:
def ENV.truthy?(key)
self[key].to_s.match?(/\A(true|t|1|yes|y|on)\z/i)
end
This method extends ENV to check for truthy boolean values from environment variables.
Usage:
if ENV.truthy?('DISABLE_THING')
# skip the thing
end
The regex handles the common variants — true, t, 1, yes, y, on — and the i flag makes it case-insensitive, so TRUE, True, T all work. Everything else returns false: false, f, 0, no, n, off, and nil all land in the same bucket.
Nil is the one to watch. ENV['MISSING_KEY'] returns nil, and the .to_s in the method converts it to "", which doesn’t match the regex. So missing keys are treated as false by default. That’s usually what you want for feature flags — opt-in by setting the variable, not opt-out.
For non-boolean ENV variables I reach for ENV.fetch with a default, or .presence when I need to distinguish empty from missing:
config.asset_host = ENV["ASSET_HOST"].presence
workers_count = ENV.fetch("WEB_CONCURRENCY", 5).to_i
generator = Rails.application.key_generator
Rails.application.config.active_record.encryption.deterministic_key =
ENV.fetch("ACTIVE_RECORD_ENCRYPTION_DETERMINISTIC_KEY") {
generator.generate_key("active_record_encryption_deterministic_key", 32).unpack1("H*")
}
It’s a small thing, but I keep seeing this pattern come up in codebases. Some projects add a gem for it. Most just hand-roll it and move on. Either way, it’s one of those Ruby-isms that catches everyone at least once.