rubyguides

Hash#fetch_values

Hash#fetch_values returns an array containing the values for the given keys. It behaves like values_at but differs in how it handles missing keys — it raises KeyError by default rather than returning nil, and it accepts an optional block for handling missing keys.

Basic Usage

h = { foo: 0, bar: 1, baz: 2 }

h.fetch_values(:baz, :foo)
# => [2, 0]

Unlike values_at, missing keys raise KeyError instead of returning nil:

h = { a: 1, b: 2 }

h.values_at(:a, :z)
# => [1, nil]

h.fetch_values(:a, :z)
# KeyError: key not found: :z

Signature

fetch_values(*keys) { |key| block }

Accepts one or more keys and returns an array of values in the same order. When a key is not found, raises KeyError unless a block is given.

Handling Missing Keys with a Block

Pass a block to provide a fallback value for missing keys:

h = { alice: 95, bob: 87 }

result = h.fetch_values(:alice, :carol) { |k| "unknown: #{k}" }
# => [95, "unknown: carol"]

The block is called only for keys that are not found. Keys that exist return their actual values.

h = { x: 10, y: 20 }

h.fetch_values(:x, :z) { |k| k.to_s.upcase }
# => [10, "Z"]

This makes fetch_values useful when you want different fallback behavior than nil but do not want to wrap every call in a begin/rescue block.

Comparison with values_at

MethodMissing key behavior
values_at(*keys)Returns nil for missing keys
fetch_values(*keys)Raises KeyError
`fetch_values(*keys) {k

Use values_at when missing keys are expected and nil is acceptable. Use fetch_values when missing keys should be an error, or when you want to compute a fallback value inline with a block.

Real-World Example

Fetching specific fields from a configuration hash with a fallback:

config = {
  host: "localhost",
  port: 5432,
  user: "app",
  password: ENV["DB_PASSWORD"]
}

# Raise an error if required keys are missing
required = [:host, :port, :user, :password]
config.fetch_values(*required)
# KeyError if password env var is not set

With a block for optional keys:

optional = [:timeout, :pool_size, :ssl_mode]

config.fetch_values(:host, :port, *optional) { |k| nil }
# Returns values for host, port, and nil for missing optional keys

Chaining with Dig

Since fetch_values returns an array, you can chain array methods on the result:

scores = { alice: 95, bob: 87, carol: 92 }

scores.fetch_values(:alice, :bob, :carol).map(&:to_f)
# => [95.0, 87.0, 92.0]

See Also