makandra / active_type

Make any Ruby object quack like ActiveRecord
MIT License
1.09k stars 74 forks source link

The Hash attributes of different instances are shared! #97

Closed spurnaye closed 7 years ago

spurnaye commented 7 years ago

I came across this issue when fixing some specs. Following points came out of my observation: Ruby 2.2.1/2.3.1 My code:

class MyClass < ActiveType::Object
  attribute :hash_attribute, :hash, default: {key1: 123, key2: 'xyz'}
   attribute :string_attribute, :string, default: 'abc'
end

instance_1 = MyClass.new
instance_2 = MyClass.new

instance_1.hash_attribute.object_id
=> 70138053336020
instance_2.hash_attribute.object_id
=> 70138053336020

is this expected?

kratob commented 7 years ago

I would have expected it, but maybe only because other solutions I know (such as the has_defaults gem) work the same way. If we find a good way to avoid this issue without breaking things, we should probably change it.

The manual fix for now is to just use a proc, such as default: -> { { key1: 123, key2: 'xyz' } }.

Theoretically, we could try to dup any default values, but I'm not totally sure about it. Users might have come to rely on the fact that a single instance is shared (maybe not in the example of a hash, but perhaps for other kinds of objects), and there are probably objects out there that don't implement dup properly. Maybe just do it for arrays and hashes?

spurnaye commented 7 years ago

Thanks for the reply! Following code has ArgumentError

attribute :hash_attribute, :hash, default: -> { {key1: 123, key2: 'xyz'} }
kratob commented 7 years ago

Right, need to use a proc instead:

attribute :hash_attribute, :hash, default: proc { {key1: 123, key2: 'xyz'} }
spurnaye commented 7 years ago

@kratob working find that way. Closing for now, but I still think those hashes should be separate objects without use of proc.