Skip to content

Commit 27411a7

Browse files
Merge branch 'hash_with_indifferent_access_fix'
The problem: Accessing a HashWithIndifferentAccess does not return the the same object that is stored in the hash (i.e. equal?) causing unexpected results: hash = HashWithIndifferentAccess.new {|h, k| h[k] = []} hash[:a] << 1 # => [1] hash[:a] # => [], expected [1] The cause: When a block is provided to generate default values the generated values are duped if they are arrays. The duped value is stored in the hash but the original value is returned when the hash is accessed. The fix: The duping is there for allowing frozen arrays containing hashes to be modified. The fix restricts the duping to this case. Note that if default function generates a frozen array an error will be raised on assignment before and after the patch. Closes rails#3811
2 parents 32c65d8 + 808592b commit 27411a7

File tree

2 files changed

+9
-1
lines changed

2 files changed

+9
-1
lines changed

activesupport/lib/active_support/hash_with_indifferent_access.rb

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -164,7 +164,8 @@ def convert_value(value)
164164
if value.is_a? Hash
165165
value.nested_under_indifferent_access
166166
elsif value.is_a?(Array)
167-
value.dup.replace(value.map { |e| convert_value(e) })
167+
value = value.dup if value.frozen?
168+
value.map! { |e| convert_value(e) }
168169
else
169170
value
170171
end

activesupport/test/core_ext/hash_ext_test.rb

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -457,6 +457,13 @@ def test_indifferent_to_hash
457457
assert_equal '1234', roundtrip.default
458458
end
459459

460+
def test_lookup_returns_the_same_object_that_is_stored_in_hash_indifferent_access
461+
hash = HashWithIndifferentAccess.new {|h, k| h[k] = []}
462+
hash[:a] << 1
463+
464+
assert_equal [1], hash[:a]
465+
end
466+
460467
def test_indifferent_hash_with_array_of_hashes
461468
hash = { "urls" => { "url" => [ { "address" => "1" }, { "address" => "2" } ] }}.with_indifferent_access
462469
assert_equal "1", hash[:urls][:url].first[:address]

0 commit comments

Comments
 (0)