rubyguides

Hash#update

update(*other_hashes) → self

Signature

update(*other_hashes) → self
update(*other_hashes) {|key, old_value, new_value| block } → self

update takes zero or more hash arguments and optionally a block. It always returns self — the same hash object that was modified in place.

Basic Usage

Give update one or more hashes and it merges them into the receiver, overwriting duplicate keys:

h = {a: 1, b: 2}
h.update({b: 3, c: 4})
h # => {:a=>1, :b=>3, :c=>4}

The original hash is modified. update returns the same object it just mutated.

Unlike merge, which returns a new hash and leaves the receiver untouched, update works destructively. This is the key difference between the two methods, and it determines which one you should reach for based on whether the surrounding code expects the original data to stay intact. For pipelines and functional-style code, prefer merge; for in-place mutation of configuration or state objects, update is the natural choice.

Block Form

When a key appears in both hashes, you can pass a block to resolve the conflict:

h = {items: 5, threshold: 10}
h.update({items: 3, threshold: 12}) { |_key, old, new| old + new }
h # => {:items=>8, :threshold=>22}

The block receives key, old_value, and new_value and its return value becomes the final value for that key. In the example above, the new items value is 5 + 3 = 8, not just 3.

The block is only called for keys that appear in both the receiver and the incoming hash. Keys that exist only in one side are passed through without invoking the block. This means the block is a conflict resolver, not a general-purpose transformation hook; (key, old, new) tuples that need custom merging logic are the only ones the block will ever see.

No Arguments

Calling update with no arguments simply returns self unchanged:

h = {x: 1, y: 2}
h.update      # => {:x=>1, :y=>2}
h.update { }  # => {:x=>1, :y=>2}  (block is ignored)

Note that this is not a copy; the method returns the same object. There is no update form that returns a modified copy like merge does.

Calling update with no arguments might seem pointless, but it can arise in metaprogramming contexts where the argument list is built dynamically. When the argument list is empty, the method is a no-op that returns self, which keeps the behavior consistent regardless of how many hashes were collected.

Multiple Hashes

You can pass multiple hashes. They are merged left to right, so later hashes win on conflicts:

h = {a: 1}
h.update({a: 2}, {a: 3}, {a: 4})
h # => {:a=>4}

Each duplicate key is overwritten by whichever hash came later in the argument list.

The left-to-right merge order means you can think of each argument as overriding the previous ones for shared keys. This is the same semantics as calling update repeatedly in a loop, but the multi-argument form is more concise and avoids creating intermediate hash states that the caller never needs to inspect. For large numbers of source hashes, this form also tends to be faster than repeated individual calls.

Alias for Hash#merge!

update is exactly the same method as Hash#merge!; they share the same implementation under the hood. Use whichever name reads better in your context. Some teams prefer merge! because it pairs naturally with merge, while others prefer update because it sounds more intentional when you are deliberately mutating state. Both names appear throughout the Ruby ecosystem in gems and frameworks, so knowing both will help when navigating unfamiliar codebases:

h = {x: 1}
h.merge!({y: 2})   # => {:x=>1, :y=>2}
h.update({z: 3})   # => {:x=>1, :y=>2, :z=>3}

Gotchas

Returns self, not a copy. Many Ruby hash methods return a new hash — merge returns a new hash, for example. update returns the mutated original, so be careful not to chain it expecting a copy back. This distinction is particularly important when the same object is referenced in multiple places throughout your program, since mutating it in one location affects every other reference to that same underlying data.

h = {a: 1}
result = h.update({b: 2})
result.equal?(h)   # => true  (same object)

Because the return value is the same object, you cannot safely use the result of update in a chain that expects a copy. If you need both the original and the merged version, call merge instead or explicitly dup the hash before calling update.

TypeError on non-Hash arguments. Each argument must be a Hash. Passing a non-hash raises TypeError:

h = {}
h.update("foo")
# => TypeError: no implicit conversion of String into Hash

Ruby does not coerce other types into hashes, so each argument must already be a Hash instance. If you are collecting data from multiple sources, convert each source to a hash before passing it to update to avoid this error at runtime.

No automatic flattening. If you pass a hash containing array values, those arrays are not recursively merged:

h = {nested: {a: 1}}
h.update(nested: {b: 2})
h # => {:nested=>{:b=>2}}  # the original :a is gone, not deep-merged

Ruby does not provide a built-in deep merge for these structures. The outer key is simply overwritten.

When you need to merge configuration from multiple sources, update processes each argument in order and lets later values override earlier ones for shared keys. This left-to-right precedence matches how most developers think about overrides: the last source wins. For non-destructive merging where you need to keep the original intact, use merge instead. The destructive nature of update makes it ideal for builder patterns where an object accumulates state across multiple method calls, each adding or overriding a subset of keys. Because it always returns self, you can call it repeatedly in a fluent interface without intermediate assignments. This makes the method particularly useful inside initializers and setup methods where several sources of configuration need to be folded together into a single object before the program moves on to its main work. This pattern appears in Ruby DSLs and configuration builders where the same receiver collects entries from several sources before being passed to the next processing stage.

See Also

  • Hash#merge — returns a new merged hash without modifying the original
  • Hash#merge! — the canonical name for this method
  • Hash#dig — safely retrieve nested hash values