In a rails app, I have model code of the form:
def do_stuff(resource)
models = Model.where(resource: resource)
operated_at = DateTime.now
models.each
Possible clue; the act of saving and reloading truncates the seconds_fraction
part of the DateTime. The date field becomes an instance of ActiveSupport::TimeWithZone
. Just saving without reloading doesn't do this; the real DateTime object is still there.
2.0.0-p195 :001 > dt = DateTest.create
2.0.0-p195 :002 > right_now = DateTime.now
2.0.0-p195 :004 > dt.created_at = right_now
2.0.0-p195 :005 > dt.created_at == right_now
=> true
2.0.0-p195 :006 > dt.save
2.0.0-p195 :007 > dt.created_at == right_now
=> true
2.0.0-p195 :008 > dt = DateTest.find(dt.id)
2.0.0-p195 :009 > dt.created_at == right_now
=> false
Edit: of course calling models.each
is going to load the models there and then because of the lazy loading behaviour. Props to the other answerer. As an experiment, try setting models
to Model.where(resource: resource).to_a
.
DateTime.now doesn't work for comparison with Database datetime object.
Example:
DateTime.now --> Fri, 25 Oct 2013 15:28:21 -0800
Time.zone.now --> Fri, 25 Oct 2013 15:27:17 PDT -07:00
I assume that this problem is due to the lazy scope that you use: models = Model.where(resource: resource)
models is a proxy collection and will be resolved by rails at some point and might be re-evaluated without you knowing exactly.
so when you change an attribute and you don't reload
the object before checking a property it might not be up to date.
You have three separate methods defined above with three separate operated_at local variables. Local variables are limited to the scope of the method which defines them.
You need to define instance variables, which persist throughout a class. For example, you could:
def Model
attr_accessor :operated_at
def do_stuff(resource)
models = Model.where(resource: resource)
operated_at = DateTime.now
models.each { |model| some_operation(model, operated_at) }
some_other_operation models, operated_at
end
def some_operation(model, operated_at)
model.date_time_field = operated_at
model.save
end
def some_other_operation(models, operated_at)
models.each do |model|
if model.date_time_field < operated_at
# do something
end
end
end
end
This would enable you to access operated_at throughout all of the class methods.