· · Matthew Ford  · 2 min read

Hash#fetch in Ruby Development

Hash#fetch in Ruby Development

In Ruby there are a number of ways you can access the value of a key within a hash. The most commonly used is the square brackets syntax hash[:key]. However, there is an alternative, which is to use Hash#fetch e.g. hash.fetch(:key).

In this post, we’re going to examine how the fetch method differs from typical access methods, the cases where it will be better to use this syntax, and how you use it.

Hash#fetch provides better handling of default values for missing keys

Let’s imagine we are storing configuration options in a hash. Ruby has a way of providing the default value for them when none is provided, by using a ternary OR statement:

config[:key] || default

But if we care that the configuration option value is false or nil, using the above will override it with the default value. This is where the fetch method can be useful, as we can provide the fetch method with a default value as a second argument and it will not override the originally set value:

config.fetch(:key, default)

Note: If we do not provide a default argument or a block, and the key is not found in the hash, then a KeyError will be raised.

Using Hash#fetch makes it easier to work with nested hashes

Another example where the fetch method is useful is when trying to cope with nested hashes. Specifically, it helps when providing default values for accessing nested keys.

Lets take the example of a configuration file again:

{  environment: {    adapter: adapter,    …  }}

Let’s say you wanted to set the default adapter in development to sqlite3 and wanted to handle the case when there was no configuration set at all for the development environment. Using the square brackets syntax:

adapter = config[:development][:adapter]

This would raise NoMethodError: undefined method `[]‘ for nil:NilClass because config[:development]would return nil.

You could get around this by writing:

adapter = (config[:development] || {})[:adapter] || “sqlite3″

but a nicer syntax would be:

adapter = config.fetch(:development, {}).fetch(:adapter, “sqlite3″)

Performance tip for Hash#fetch

There is a performance issue with the fetch method—the default value always gets evaluated, even if the key is present in the hash. This might not be an issue if the value is simple (such as a string) or quick to calculate, but if it’s an API call or database query then you can quickly run into performance issues.

Let’s imagine we want to retrieve a user’s coordinates:

user_location = {  coordinates: {    lat: latitude,    lng: longitude  },  ip: user_request_ip}

If the coordinates are not provided in the hash we will look up the coordinates from the IP address using an external service CoordinatesFetcher.

If we were to use the default value as in the previous examples:

user_location.fetch(:coordinates, CoordinatesFetcher.from_ip(user_location[:ip]))

It will call the CoordinatesFetcher every time, regardless of whether the coordinates are present in the hash, but to avoid this you just need to set the default value as a block:

user_location.fetch(:coordinates) { |ul| CoordinatesFetcher.from_ip(ul[:ip]) }

That’s it for this time. You can read more about fetch method in the ruby documentation at API dock.

Oren Dobzinski also has a nice write up of using the fetch method for default values in service objects at Re-factor.

If you want to find more interesting ideas and best practices about RoR development have a look at the Active Support Core Extensions guide.

Do you need help with your application?

At Bit Zesty, we specialise in building and maintinaing bespoke software and intergrating AI into existing applications.

Looking to build an application, but unsure of the price? Keen to discuss our experience, processes and availability?

Back to Blog

Related Posts

View all
Brighton Ruby 2024

Brighton Ruby 2024

Brighton Ruby 2024 was nothing short of amazing. It brought together passionate Ruby developers from around the world to share knowledge, network, and have fun.

Ruby on Rails: Top 5 Gems to Enhance your Application

Ruby on Rails: Top 5 Gems to Enhance your Application

Creating a Ruby on Rails app can be a challenging task, but it can be made easier by utilizing different gems. These gems consist of third-party code libraries that can significantly speed up the development process. While some of these gems are necessary for Rails,…