在rails应用程序中,我有以下形式的模型代码:
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
在这种情况下,将始终执行some_other_operation的“do something”块。更奇怪的是,如果我在没有所有已定义函数的控制台中进行设置,则比较可以正常工作。例如:
> model = Model.first
> time_var = DateTime.now
> model.last_imported_at = time_var
=> Fri, 25 Oct 2013 21:14:06 +0000
> model.save
=> true
> model.last_imported_at < time_var
=> false
> model.last_imported_at == time_var
=> true
最后,如果在some_other_operation
中我改为按以下方式进行比较:
if model.date_time_field.to_i < operated_at.to_i
# do something
end
只有在预期时才会达到'do something'块。我怀疑这是因为to_i
方法将删除DateTime对象上定义的秒的分数,并且operated_at
变量实际上被重新定义为每个方法范围的DateTime.now
。如果是这种情况,那么我想我的问题是如何强制operated_at
不为每个范围重新定义?
答案 0 :(得分:3)
可能的线索;保存和重新加载的行为会截断DateTime的seconds_fraction
部分。日期字段成为ActiveSupport::TimeWithZone
的实例。只是保存而不重新加载不会这样做;实际的DateTime对象仍在那里。
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
编辑:当然调用models.each
将在那里加载模型,然后由于延迟加载行为。道具给另一个回答者。作为实验,请尝试将models
设置为Model.where(resource: resource).to_a
。
答案 1 :(得分:1)
您有三个单独的方法,上面定义了三个独立的operate_at局部变量。局部变量仅限于定义它们的方法的范围。
您需要定义实例变量,这些变量在整个类中都存在。例如,您可以:
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
这使您可以在所有类方法中访问operate_at。
答案 2 :(得分:0)
我认为此问题是由于您使用的惰性范围造成的:models = Model.where(resource: resource)
模型是一个代理集合,将在某些时候由rails解决,并且可能在您不确切知道的情况下重新评估。
所以当您更改属性并且在检查属性之前没有reload
该对象时,它可能不是最新的。
答案 3 :(得分:0)
DateTime.now无法与Database datetime对象进行比较。
示例:
DateTime.now - &gt; 星期五,2013年10月25日15:28:21 -0800
Time.zone.now - &gt; 星期五,2013年10月25日15:27:17 PDT -07:00