Peter Yeremenko
Peter Yeremenko

Reputation: 1279

Really odd issues with Time when it used within a scope

There is a page in my Rails-app where tours should be displayed so that the start_date field is equal to tomorrow's date (in GMT+00)

I use default timezone in application.rb

# Set Time.zone default to the specified zone and make Active Record ...
# Run "rake -D time" for a list of tasks for finding time zone names. Default is UTC.
# config.time_zone = 'Central Time (US & Canada)'

However there in is a problem. Instead of the page displaying tour dates starting from tomorrow, I see dates from today and even yesterday.

I put to the page the following information:

Time.zone                (GMT+00:00) UTC
Date.today_local_zone    2013-11-20
Date.today               2013-11-20
Time.now                 2013-11-20 00:48:21 +0000

Code in my controller:

puts "... #{ Tour.upcoming.order('start_date ASC').to_sql }"
@tours = Tour.upcoming.order('start_date ASC')

And the scope in Tour model

class Tour < ActiveRecord::Base 
  attr_accessible :start_date, :title
  scope :upcoming, where('tours.start_date > ?', Date.today_local_zone)
end

Briefly about my today_local_zone method:

class Date
  def self.today_local_zone
    Time.zone.now.to_date
  end
end

Here is a line from my logs (the date the query is different from the date in the logs)

2013-11-20T00:48:21.178380+00:00 app[web.1]: ... SELECT "tours".* FROM "tours"  WHERE (tours.start_date > '2013-11-19') ORDER BY start_date ASC 

UPD:

I tried to log value of Time.zone.now.to_s.to_date. It's value is correct.

Please also look at my gist with:

Upvotes: 0

Views: 97

Answers (1)

Peter Goldstein
Peter Goldstein

Reputation: 4545

I missed this on first review. The problem is in your scope statement:

scope :upcoming, where('tours.start_date > ?', Date.today_local_zone)

This definition is wrong. It loads Date.today_local_zone when the class is loaded. You need to wrap it in a Proc. So it should be:

scope :upcoming, lambda { where('tours.start_date > ?', Date.today_local_zone) }

which ensures that Date.today_local_zone is executed each time the scope is used.

Upvotes: 1

Related Questions