Hash#has_key?
These four methods check whether a hash contains a specific key. They are aliases for each other — you can use whichever reads most naturally in your code.
Syntax
hash.has_key?(key) # => true or false
hash.key?(key) # => true or false
hash.include?(key) # => true or false
hash.member?(key) # => true or false
Parameters
| Parameter | Type | Description |
|---|---|---|
key | Object | The key to search for in the hash |
Return Value
Returns true if the hash contains the given key, false otherwise.
Description
Ruby provides four identical methods for checking key existence:
has_key?— The most descriptive name. Readable in tests and conditionals.key?— Concise. Common in Rails and Ruby codebases.include?— Familiar if you come from Python or C++.member?— The oldest alias, dating back to Ruby 1.8.
All four methods do exactly the same thing. Choose based on readability in your specific context.
The key difference between these methods and bracket notation (hash[key]) is that bracket notation returns nil for missing keys, which is ambiguous — you cannot tell whether the key exists with a nil value or the key is missing entirely. These methods always return a boolean.
Examples
Basic key checking
user = { name: "Alice", age: 30, city: "London" }
user.has_key?(:name) # => true
user.has_key?(:email) # => false
user.key?(:age) # => true
Using in conditionals
config = { environment: "production", debug: false }
if config.key?("environment")
puts "Running in #{config["environment"]} mode"
end
# => Running in production mode
Different aliases, same result
data = { a: 1, b: 2 }
data.has_key?(:a) # => true
data.key?(:a) # => true
data.include?(:a) # => true
data.member?(:a) # => true
With string keys
params = { "controller" => "users", "action" => "show" }
params.has_key?("controller") # => true
params.has_key?(:controller) # => false - different key type!
# Convert string keys to symbols if needed
params.transform_keys(&:to_sym).has_key?(:controller)
# => true
Note that symbol keys and string keys are distinct in Ruby hashes.
Comparison with bracket notation
scores = { alice: nil, bob: 100 }
scores[:alice] # => nil (ambiguous!)
scores[:charlie] # => nil (also nil!)
scores.has_key?(:alice) # => true - knows the key exists
scores.has_key?(:charlie) # => false - key is missing
Common Patterns
Safe value retrieval
settings = { theme: "dark" }
# Instead of this:
theme = settings[:theme] || "light"
# Do this (cleaner):
theme = settings.fetch(:theme, "light")
Validation
required_keys = [:name, :email, :password]
user_input = { name: "Bob", email: "bob@example.com" }
required_keys.each do |key|
unless user_input.key?(key)
raise ArgumentError, "Missing required key: #{key}"
end
end
# Raises: Missing required key: password
Performance
These methods run in O(1) average time because hashes use internal lookup tables. The time complexity does not grow with hash size.
See Also
hash-fetch— Fetch a value with a default or blockhash-dig— Safely access nested values