Search code examples
ruby-on-railsrubyhashclonedup

Recursive function in ruby is overwriting nested attributes of cloned(object.dup) variable


I have a hash like this:

entity = {1=> nil, 2 => {3 => nil, 4 => 1}}

I wrote a function which can remove the null values of the given entity using recursion.

def clear_null_values(entity)
   entity.each do |key, value|
     if value == nil || value.blank?
       entity.delete(key)
     elsif value.is_a? Hash
       clear_null_values(value)
       entity.delete(key) if value.blank?
     end
   end
end 

And also I need the original entity as well for other purposes. So I duplicated the hash variable and then cleared the null values.

final_entity = entity.dup
clear_null_values(entity)
puts entity
puts final_entity

Result:

{2 => {4 => 1}}
{1=> nil, 2 => {4 => 1}} # the nested values are overwritten.

Ideally, the final_entity should be the same as original entity.

Question1: Why is the entity.dup copying only outerhash?

Question2: How to make final_entity the exactly copy of original entity i.e., even if we modify entity then also final_entity shouldn't change?


Solution

  • Try using deep_dup instead, your original code only dup-ed the outermost hash.

    final_entity = entity.deep_dup
    clear_null_values(entity)
    puts entity
    puts final_entity
    

    Outputs:

    {2=>{4=>1}}
    {1=>nil, 2=>{3=>nil, 4=>1}}
    

    Note: Rails also adds Hash#compact, which you could use to simplify clear_null_values.