Rails config.time_zone和datetime属性更新

时间:2011-12-15 19:09:52

标签: ruby-on-rails ruby-on-rails-3 activerecord ruby-on-rails-3.1

在我的申请中,我有:config.time_zone = 'Warsaw'

我遇到一个奇怪的问题,就是看起来Rails在比较datetime字段方面遇到了问题。 如果我更改1小时后的日期时间(华沙目前在时区+0100),即使字段已更改,Rails也不会更新数据库。但是,如果我再次更改字段,则更新将转到数据库。

示例:

(Rails 3.1.0,ruby-1.9.2-p290,fresh rails app):

$ rails g model User starts_at:datetime
$ rake db:migrate
$ rails c
Loading development environment (Rails 3.1.0)
ruby-1.9.2-p290 :001 > u = User.create({:starts_at => "2011-01-01 10:00"})
SQL (21.3ms)  INSERT INTO "users" ("created_at", "starts_at", "updated_at") VALUES (?, ?, ?)  [["created_at", Tue, 13 Dec 2011 11:32:50 CET +01:00], ["starts_at", Sat, 01 Jan 2011 10:00:00 CET +01:00], ["updated_at", Tue, 13 Dec 2011 11:32:50 CET +01:00]]
 => #<User id: 1, starts_at: "2011-01-01 09:00:00", created_at: "2011-12-13 10:32:50", updated_at: "2011-12-13 10:32:50"> 
ruby-1.9.2-p290 :002 > u.starts_at
 => Sat, 01 Jan 2011 10:00:00 CET +01:00 # datetime created
ruby-1.9.2-p290 :003 > u.starts_at = "2011-01-01 09:00:00" # new datetime with one hour back
 => "2011-01-01 09:00:00" 
ruby-1.9.2-p290 :004 > u.starts_at
 => Sat, 01 Jan 2011 09:00:00 CET +01:00 # changed datetime
ruby-1.9.2-p290 :005 > u.save 
 => true 
ruby-1.9.2-p290 :006 > u.starts_at = "2011-01-01 09:00:00"
 => "2011-01-01 09:00:00" 
ruby-1.9.2-p290 :007 > u.save
   (0.3ms)  UPDATE "users" SET "starts_at" = '2011-01-01 08:00:00.000000', "updated_at" = '2011-12-13 10:33:17.919092' WHERE "users"."id" = 1
 => true 

我已经在这个新应用中测试了它,因为我在更大的应用程序中遇到了这个问题。到底是怎么回事?我试图浏览Rails代码,尝试在控制台中“手动”重新复制相关代码(如update,assign_attributes,甚至检查time_zone_conversion)并且它有效,但不是在'真实世界'中..

1 个答案:

答案 0 :(得分:3)

看起来你偶然发现了类似的问题。

问题似乎在这里: https://github.com/rails/rails/blob/3-1-stable/activerecord/lib/active_record/attribute_methods/dirty.rb#L62

如果测试值改变了它的轨道,它比较旧的&amp;新:

  

old =来自缓存(当前时区的时间)

     

new =保存在数据库中的UTC时间(+00:00)

如果时间差是UTC偏移量,则上述错误地成功(幸运的是,新的缓存值保持预期的变化)。

下一次保存/更新与新的(和正确的)缓存值进行比较,并将该字段标记为已更改。

编辑:

完成一些测试,这对我很有用:

https://github.com/rails/rails/blob/3-1-stable/activerecord/lib/active_record/attribute_methods/time_zone_conversion.rb#L50

更改

write_attribute(:#{attr_name}, original_time)

write_attribute(:#{attr_name}, time.in_time_zone('UTC').to_s)

鲍里斯