Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix handling of dirty time zone aware attributes #9073

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
28 changes: 28 additions & 0 deletions 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*

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great explanation 👍

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @guilleiguaran! :)

* PostgreSQL ranges type support. Includes: int4range, int8range,
numrange, tsrange, tstzrange, daterange

Expand Down
Expand Up @@ -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
Expand Down
2 changes: 2 additions & 0 deletions activerecord/test/cases/dirty_test.rb
Expand Up @@ -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

Expand Down