Обновление атрибутов Rails config.time_zone и datetime - PullRequest
1 голос
/ 15 декабря 2011

В моем заявлении у меня есть: config.time_zone = 'Warsaw'

У меня странная проблема в том, что у Rails возникают проблемы со сравнением полей даты и времени. Если я изменю дату и время на 1 час назад (а Варшава в настоящее время находится в часовом поясе +0100), Rails не будет обновлять базу данных, даже если поле изменилось. Однако, если я еще раз изменю поле, обновление перейдет в базу данных.

Пример:

(Rails 3.1.0, ruby-1.9.2-p290, приложение свежие рельсы):

$ 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 Ответ

3 голосов
/ 20 декабря 2011

похоже, что вы наткнулись на похожую проблему.

Проблема, кажется, здесь: https://github.com/rails/rails/blob/3-1-stable/activerecord/lib/active_record/attribute_methods/dirty.rb#L62

Когда он проверяет, было ли изменено значение, он сравнивает старый и новый:

old = Из кэша (который является временем в вашем текущем часовом поясе)

new = Время в формате UTC (+00: 00), сохраненное в базе данных

Если разница во времени равна смещению UTC, вышеприведенное ошибочно выполняется (к счастью, новое кэшированное значение содержит предполагаемое изменение).

Следующее сохранение / обновление сравнивается с новым (и правильным) кэшированным значением и помечает поле как измененное.

EDIT:

Выполнено несколько тестов, у меня это хорошо работает:

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)

Борис

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...