diff --git a/activerecord/CHANGELOG.md b/activerecord/CHANGELOG.md index 278baee68f956..71295aaac91ce 100644 --- a/activerecord/CHANGELOG.md +++ b/activerecord/CHANGELOG.md @@ -1,5 +1,33 @@ ## Rails 4.0.0 (unreleased) ## +* Fix handling of dirty time zone aware attributes + + Previously, when `time_zone_aware_attributes` were enabled, after + changing a datetime or timestamp attribute and then changing it back + to the original value, `changed_attributes` still tracked the + attribute as changed. This caused `[attribute]_changed?` and + `changed?` methods to return true incorrectly. + + Example: + + in_time_zone 'Paris' do + order = Order.new + original_time = Time.local(2012, 10, 10) + order.shipped_at = original_time + order.save + order.changed? # => false + + # changing value + order.shipped_at = Time.local(2013, 1, 1) + order.changed? # => true + + # reverting to original value + order.shipped_at = original_time + order.changed? # => false, used to return true + end + + *Lilibeth De La Cruz* + * PostgreSQL ranges type support. Includes: int4range, int8range, numrange, tsrange, tstzrange, daterange diff --git a/activerecord/lib/active_record/attribute_methods/time_zone_conversion.rb b/activerecord/lib/active_record/attribute_methods/time_zone_conversion.rb index 7701001da97bc..e3c5dc48230be 100644 --- a/activerecord/lib/active_record/attribute_methods/time_zone_conversion.rb +++ b/activerecord/lib/active_record/attribute_methods/time_zone_conversion.rb @@ -40,9 +40,9 @@ def #{attr_name}=(original_time) time = time.is_a?(String) ? Time.zone.parse(time) : time.to_time rescue time end time = time.in_time_zone rescue nil if time - changed = read_attribute(:#{attr_name}) != time + previous_time = attribute_changed?("#{attr_name}") ? changed_attributes["#{attr_name}"] : read_attribute(:#{attr_name}) write_attribute(:#{attr_name}, original_time) - #{attr_name}_will_change! if changed + #{attr_name}_will_change! if previous_time != time @attributes_cache["#{attr_name}"] = time end EOV diff --git a/activerecord/test/cases/dirty_test.rb b/activerecord/test/cases/dirty_test.rb index 4ac82f6880dcb..c7d2ba607386e 100644 --- a/activerecord/test/cases/dirty_test.rb +++ b/activerecord/test/cases/dirty_test.rb @@ -79,6 +79,8 @@ def test_time_attributes_changes_with_time_zone assert pirate.created_on_changed? assert_kind_of ActiveSupport::TimeWithZone, pirate.created_on_was assert_equal old_created_on, pirate.created_on_was + pirate.created_on = old_created_on + assert !pirate.created_on_changed? end end