Hash#except
hash.except(*keys) -> hash The except method returns a new hash with one or more specified keys removed. The original hash remains unchanged, making this a non-destructive operation. This method was introduced in Ruby 3.0 as part of the collection refinements.
Signature
hash.except(*keys) → new_hash
Parameters
| Parameter | Type | Description |
|---|---|---|
*keys | Symbol, String | One or more keys to exclude from the returned hash. Both symbol and string keys are supported. |
Return Value
Returns a new Hash containing all key-value pairs from the original hash except those whose keys match the arguments.
Basic Usage
user = { name: 'Alice', email: 'alice@example.com', password: 'secret123', token: 'abc123' }
user.except(:password, :token)
# => {:name=>"Alice", :email=>"alice@example.com"}
The original hash stays unchanged:
user # => {:name=>"Alice", :email=>"alice@example.com", :password=>"secret123", :token=>"abc123"}
Excluding Multiple Keys
You can exclude as many keys as you need:
config = { host: 'localhost', port: 3000, debug: true, verbose: true, secret: 'key' }
config.except(:secret, :debug)
# => {:host=>"localhost", :port=>3000, :verbose=>true}
Symbol vs String Keys
Symbol and string keys are treated as distinct. Excluding :id does not remove 'id':
params = { id: 1, 'id' => 'two', name: 'Bob' }
params.except(:id)
# => {"id"=>"two", :name=>"Bob"}
params.except('id')
# => {:id=>1, :name=>"Bob"}
Common Use Case: Filtering Sensitive Data
A frequent application is removing sensitive attributes before logging or passing hashes to external services:
credentials = {
username: 'alice',
password: 'supersecret',
api_key: 'sk-1234567890',
name: 'Alice Smith'
}
safe_credentials = credentials.except(:password, :api_key)
safe_credentials
# => {:username=>"alice", :name=>"Alice Smith"}
This pattern prevents accidental exposure of secrets in logs or error reports:
def create_user(params)
# Remove sensitive fields before logging
safe_params = params.except(:password, :api_key)
logger.info("Creating user: #{safe_params}")
# ... rest of method
end
Chaining with Other Hash Methods
except returns a hash, so you can chain it with other hash methods:
data = { a: 1, b: 2, c: 3, d: 4, secret: 'hidden' }
data.except(:secret).select { |_k, v| v > 1 }
# => {:b=>2, :c=>3, :d=>4}
See Also
hash#slice— Returns a new hash containing only the specified keys (the inverse operation)hash#transform_keys— Transform keys in a hash using a block or hash argumenthash#merge— Combine multiple hashes into a new hash