Querying for Today's Date with ActiveRecord
3.10.2017
Seems like it should be simple, right? Well it is, locally. But when pushed to production, I ran into some odd bugs having to do with this seemingly simple task.
I built an application for personal trainers to post workouts for their clients. (It's here, but still very much a work in progress). One of the features is that when an athlete (or a coach of that athlete) goes to their home page, their training session for that day is featured. It works like this: When a workout is created, it has an attribute, date, that takes a ruby Date object. Then, when querying the database, I just ask for all the workouts where the date is Date.today (and the athlete is the current one). The method looked like this:
scope :today, ->(athlete) { where(date: Date.today).where(athlete_id: athlete.id) }
This worked great until I pushed to production (and maybe that wasn't even the issue, but that's where I noticed it). I found that the featured workout was not today's, but tomorrow's (or nothing, if there wasn't a workout for tomorrow). And when I asked the Rails console what Date.today was, sure enough, it said tomorrow.
Why? Well, I'm pretty sure it's because the time zone defaulted to UTC, aka Greenwich Mean Time. So by 4pm, it was "tomorrow." So the first step was to actually tell my app what time zone I want to default to. In config/application.rb, inside of the Application class, that looks like this:
config.time_zone = 'Pacific Time (US & Canada)' config.active_record.default_timezone = :local
But this didn't quite work. The query was still turning up the wrong date in production, or nothing at all. So I turned to my good friend Stack Overflow, who introduced me to this thread.
As I understand it, Date.today is not specific enough, as the Date object being created in ActiveRecord has a time stamp connected to it. Comparing my old query vs the one suggested in the SO thread in the Rails console showed this:
Date.today # => Fri, 10 Mar 2017
Time.zone.now.beginning_of_day # => Fri, 10 Mar 2017 00:00:00 PST -08:00
Plugging that into my query looks like this:
scope :today, ->(athlete) { where(date: Time.zone.now.beginning_of_day).where(athlete_id: athlete.id) }
I pushed back to production and...nothing. It didn't work for workouts previously posted. BUT, when I posted a new one for "today" - it worked! I will check again later (once it's past midnight in England) to double check, but I'm pretty sure this takes care of it. I'll update this post to reflect my results.
Perhaps there's a simpler solution that this, or I'm not understanding it all perfectly, but it's working, so I'll take it!
Other Posts
The Best Projects Can Be Done in a Weekend
Everyone Has Something To Offer
Book Thoughts: Capital and Ideology
Naive Diffie-Hellman Implementation in Ruby
When Does the Magic Comment Work, and When Does it Not?
Benchmarking Arrays Full of Nils
Go, and When It's Okay to Learn New Things
Grouping Records by Month with Ruby
Add Timestamps to Existing Tables in Rails
The Busy and (Somewhat) Fit Developer
TuxedoCSS and the Rails Asset Pipeline
Gem You Should Know About: auto_html