Ruby Dup 了一个 rails cache, dup 的对象改了以后 cache 的内容改变了!!

betterthornbird · 2014年07月10日 · 最后由 betterthornbird 回复于 2014年07月14日 · 2483 次阅读

无解。。颠覆了我的世界观。

大家可以在 console 里面试试。

使用的 ruby 版本是 1.8.7 Rails 2.3.17

a = {"array_item_0" => [{"attr_0" => 0}, {"attr_1" => 1}], "array_item_1" => [{"attr_2" => 2}, {"attr_3" => 3}]}

Rails.cache.write "test_a", a, :expires_in => 1.hours; nil

b = (Rails.cache.read "test_a").dup;nil

merge_test = [{"additional_attr_0" => 0}, {"additional_attr_1" => 1}]

b["array_item_0"].each_with_index {|item, index| item.merge! merge_test[index]}

Rails.cache.read "test_a"
>> {"array_item_1"=>[{"attr_2"=>2}, {"attr_3"=>3}], "array_item_0"=>[{"additional_attr_0"=>0, "attr_0"=>0}, {"additional_attr_1"=>1, "attr_1"=>1}]}

不用 merge! 试试呢?还是变化了

a = {"array_item_0" => [{"attr_0" => 0}, {"attr_1" => 1}], "array_item_1" => [{"attr_2" => 2}, {"attr_3" => 3}]}

Rails.cache.write "test_a", a, :expires_in => 1.hours; nil

b = (Rails.cache.read "test_a").dup;nil

merge_test = [{"additional_attr_0" => 0}, {"additional_attr_1" => 1}]

b["array_item_0"].each_with_index {|item, index| b["array_item_0"][index] = item.merge merge_test[index]}

Rails.cache.read "test_a"
>> {"array_item_1"=>[{"attr_2"=>2}, {"attr_3"=>3}], "array_item_0"=>[{"additional_attr_0"=>0, "attr_0"=>0}, {"additional_attr_1"=>1, "attr_1"=>1}]}

难道只有用这种方式 才能保证 cache 不会变?

a = {"array_item_0" => [{"attr_0" => 0}, {"attr_1" => 1}], "array_item_1" => [{"attr_2" => 2}, {"attr_3" => 3}]}

Rails.cache.write "test_a", a, :expires_in => 1.hours; nil

b = (Rails.cache.read "test_a").dup;nil

merge_test = [{"additional_attr_0" => 0}, {"additional_attr_1" => 1}]

c = {}

c["array_item_0"] ||= []

b["array_item_0"].each_with_index {|item, index| c["array_item_0"] << (item.merge merge_test[index])}

Rails.cache.read "test_a"
>> {"array_item_0"=>[{"additional_attr_0"=>0, "attr_0"=>0}, {"additional_attr_1"=>1, "attr_1"=>1}]}

初步猜测:拷贝层次和嵌套 Hash 还没有理论依据

2 楼 已删除

中间是不是共用了一个 singleton?

你们是不是改了 Rails.cache read 和 write 的行为啊?

5 楼 已删除

做 merge test 之前,为啥不先打印出 object_id 来看看 a,b 到底是否是同一个对象呢?

#6 楼 @Victor 打印对象是一方面,但是也不会改变 cache 吧 ?

#4 楼 @zgm 没有改 read write 行为

#6 楼 @Victor 打出来过 不是同一个对象 你也可以自己做做测试

Rails 4.1 ruby 2.1.2 查无此事

#9 楼 @betterthornbird 我没有 Rails 2.3 也不想安。我是 ruby 211 和 rails 41 没有问题

#11 楼 @Victor @aptx4869 ruby-2.1.2 && Rails 4.1.1 确实无此事

#9 楼 @betterthornbird 那太奇怪了,不知道为什么会改变 cache 的内容。

#13 楼 @zgm 是啊 搞得我现在用 cache 都小心翼翼 生怕哪里把它改写了 还好项目的 ruby 和 rails 版本要升级了

需要 登录 后方可回复, 如果你还没有账号请 注册新账号