Using dup vs deep dup in Ruby on Rails
Software Craftsmanship Ruby on Rails Dup Deep DupIn Ruby on Rails, the .dup
method is commonly used to create a duplicate of an object, allowing modifications without affecting the original.
However, it’s crucial to understand its limitations, especially when dealing with nested structures.
The Shallow Copy Pitfall
Consider the following scenario with a user object:
user = { name: 'Hello', email: 'hello@gmail.com', address: { city: 'Delhi' } }
user_dup = user.dup
user_dup[:email] = 'world@gmail.com'
puts user_dup[:email]
# world@gmail.com
puts user[:email]
# hello@gmail.com
Here, modifying the duplicated object (user_dup
) doesn’t impact the original object (user
), and everything seems fine.
However, things take an unexpected turn when dealing with nested attributes:
user_dup[:address][:city] = 'Mumbai'
puts user_dup[:address][:city]
# Mumbai
puts user[:address][:city]
# Mumbai
Surprisingly, changing the city for user_dup
also alters the city for the original user
object.
The culprit here is the Shallow Copy nature of .dup
.
While it creates a new object with a different object_id
, the nested attributes still reference the original object.
This leads to unintended side effects when modifying nested values.
The Solution:
To avoid such pitfalls, it’s recommended to use the deep_dup
method instead of dup
when dealing with objects containing deep nesting.
Let’s revisit the previous example with deep_dup
:
user = { name: 'Hello', email: 'hello@gmail.com', address: { city: 'Delhi' } }
user_deep_dup = user.deep_dup
user_deep_dup[:address][:city] = 'Mumbai'
puts user_deep_dup[:address][:city]
# Mumbai
puts user[:address][:city]
# Delhi
By using deep_dup
, we ensure that the duplicated object is a deep copy, preventing unintended modifications to nested attributes.
This practice is particularly crucial when dealing with complex data structures in Ruby on Rails applications.
Conclusion
Understanding the distinction between dup
and deep_dup
is vital for avoiding unexpected behaviors, especially when working with nested objects in Ruby on Rails.
While dup
creates a shallow copy, retaining references to nested attributes, deep_dup
ensures a complete duplication, safeguarding against unintended side effects.
Choosing the appropriate method based on the depth of your data structure is key to maintaining the integrity of your objects.