This Week I Learned #8
Adding environment-based HTTP authentication to a Rails app, how to filter tailed log output, and a great habit for writing clearer, self-documenting code.
How to Password-Protect a Staging Environment
At first I considered making the conditional if Rails.env.staging?
but by using environment variables, it’s easy to enable authentication in any environment (perhaps a production server before launch) without needing to push new code.
# application_controller.rb
before_filter :password_protect
def password_protect
if ENV['HTTP_USERNAME'] && ENV['HTTP_PASSWORD']
authenticate_or_request_with_http_basic do |u, p|
u == ENV['HTTP_USERNAME'] && p == ENV['HTTP_PASSWORD']
end
end
end
How to Filter Tailed Logs
This is one of those Linux tricks I should have picked up a long time ago, but I’m finally glad I did. When tailing a production log looking for a particular action, I was overwhelmed by the sheer volume of what was being output. Then I realized you can pipe the log output in to grep
to show only lines matching a string in which you’re interested:
heroku logs -t -r production | grep somethingspecial
Now, I’ll only see log lines containing “somethingspecial”.
A Habit for Writing Self-Documenting Code
Extract booleans used in conditionals into variables. This is an idea from Peter Nixey in his excellent post, “How to be a Great Software Developer”. This habit not only helps keep line-length manageable when you have long conditionals, but more importantly leads to more readable, intelligble code. What’s more, by having to describe what it is you’re checking for, you may realize you’ve missed a case. For example, in transcribing user.actions.empty?
into the intention-revealing variable user_is_not_yet_active
, I might realize that there is actually an additional way I had missed in which a user might be considered active.
So instead of
if (user.created_at < 10.minutes.ago && user.actions.empty?)
# Do something
end
consider
user_is_recently_created = user.created_at < 10.minutes.ago
user_is_not_yet_active = user.actions.empty?
if user_is_recently_created && user_is_not_yet_active
# Do something
end
Of course, if you use these booleans in more than one place, you should consider moving them into the model to keep things DRY:
# app/models/user.rb
def recently_created?
created_at < 10.minutes.ago
end
def not_yet_active?
actions.empty?
end
So that you can write
if user.recently_created? && user.not_yet_active?
# Do something
end