Problem with dup in HashWithIndifferentAccess

Hi not sure if this is where I should post this problem but since upgrading to rails 3.07 dup is not working as expected

basically in method I have this         dup_row = row.dup         #then I delete a row of my original hash         row[:athlete].delete(:sports) if !row[:athlete][:sports].nil?

   pretty simple but what is happening is it is deleting from the dup and the original here is the debug code of the original and dup just after deleting the sports

original hash values

{"athlete"=>{"first_name"=>"DaveG5600", "gender"=>"M", "hometown_id"=>"40", "birthplace_id"=>"30", "last_name"=>"test"}, "leagues"=>{"league"=>{"id"=>"821", "start_year"=>"1983", "end_year"=>"2003"}}, "clubs"=>{"club"=>[{"id"=>"11802", "start_year"=>nil, "end_year"=>nil}, {"id"=>"1403", "start_year"=>nil, "end_year"=>nil}]}, "schools"=>{"school"=>{"id"=>nil, "start_year"=>nil, "end_year"=>nil}}, "sports"=>{"sport"=>{"id"=>"102", "start_year"=>"1985", "end_year"=>"1986", "sport_roles"=>"10"}}}}

dup row (notice sports is missing which even though I am not deleting from this hash) {"athlete"=>{"first_name"=>"DaveG5600", "gender"=>"M", "hometown_id"=>"40", "birthplace_id"=>"30", "last_name"=>"test"}, "leagues"=>{"league"=>{"id"=>"821", "start_year"=>"1983", "end_year"=>"2003"}}, "clubs"=>{"club"=>[{"id"=>"11802", "start_year"=>nil, "end_year"=>nil}, {"id"=>"1403", "start_year"=>nil, "end_year"=>nil}]}, "schools"=>{"school"=>{"id"=>nil, "start_year"=>nil, "end_year"=>nil}}}}

row (this is where I expect to have the sport value deleted which is does) {"athlete"=>{"first_name"=>"DaveG5600", "gender"=>"M", "hometown_id"=>"40", "birthplace_id"=>"30", "last_name"=>"test"}, "leagues"=>{"league"=>{"id"=>"821", "start_year"=>"1983", "end_year"=>"2003"}}, "clubs"=>{"club"=>[{"id"=>"11802", "start_year"=>nil, "end_year"=>nil}, {"id"=>"1403", "start_year"=>nil, "end_year"=>nil}]}, "schools"=>{"school"=>{"id"=>nil, "start_year"=>nil, "end_year"=>nil}}}}   e

Very strange not sure if rails or ruby issue.

dup produces a shallow copy 1. So in your case, when you call dup, it creates a copy of the hash, but not the objects that the hash points to. In order to get the behavior you want, you would need to do a deep copy. One way to do that would be:

dup_row = Marshal.load(Marshal.dump(row))

This is idiomatic ruby behavior and shouldn’t be affected by rails, though I can’t say for certain it isn’t.

Allen Madsen http://www.allenmadsen.com