Prevent changes_to_save from mutating attributes

When an array of hashes is added to a `HashWithIndifferentAccess`, the
hashes are replaced with HWIAs by mutating the array in place.

If an attribute's value is an array of hashes, `changes_to_save` will
convert it to an array of HWIAs as a side-effect of adding it to the
changes hash.

Using `merge!` instead of `[]=` fixes the problem, as `merge!` copies
any array values in the provided hash instead of mutating them.
This commit is contained in:
Eugene Kenny 2018-04-08 23:06:48 +01:00
parent d729bc7488
commit 80a09caedc
2 changed files with 9 additions and 1 deletions

View File

@ -23,7 +23,7 @@ module ActiveModel
attr_names.each_with_object({}.with_indifferent_access) do |attr_name, result|
change = change_to_attribute(attr_name)
if change
result[attr_name] = change
result.merge!(attr_name => change)
end
end
end

View File

@ -473,6 +473,14 @@ class DirtyTest < ActiveRecord::TestCase
end
end
def test_changes_to_save_should_not_mutate_array_of_hashes
topic = Topic.new(author_name: "Bill", content: [{ a: "a" }])
topic.changes_to_save
assert_equal [{ a: "a" }], topic.content
end
def test_previous_changes
# original values should be in previous_changes
pirate = Pirate.new