Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

Don’t Be Liberal When Being Aggressive: Ruby Hash’s Fetch With Defaults

DZone's Guide to

Don’t Be Liberal When Being Aggressive: Ruby Hash’s Fetch With Defaults

Hash is an extremely flexible structure and we can't imagine our code without it. However, this flexibility comes with a hidden cost—uncertainty.

· Web Dev Zone ·
Free Resource

Jumpstart your Angular applications with Indigo.Design, a unified platform for visual design, UX prototyping, code generation, and app development.

Hash is an extremely flexible structure and we can't imagine our code without it. However, this flexibility comes with a hidden cost—uncertainty. Consider this code:

def find_exchange_rate(data)
  amount = data[:amount]
  from_currency = data[:from_currency]
  to_currency = data[:to_currency]

  ... #persistence access code
end


In order to prevent situations where  data  attributes aren't defined, fetch comes to help.

def show_exchange_rate(data)
  amount = data.fetch(:amount)
  from_currency = data.fetch(:from_currency)
  to_currency = data.fetch(:to_currency)
end


If from_currency or to_currency isn't defined, the application fails. Now, the code is much more secure.

Here's the moment when you have to decide what the policy will be. One option is to go with exception raised when a key is not present, but another approach is to use a default value.

from_currency = data.fetch(:from_currency) { DEFAULT_CURRENCY }


At first glance, it's a very convenient way to make the application work. However, it's not. It's rather a first step to making your application a source of falsehood. It's just like I said in the title—we're both aggressive and liberal because we enforce you to pass the param, but in case you forget we don't tell you about it.

It's enough if your client makes a misspelling in his client code, for example this:

data = {
  value: 1000,
  from_curency: 'EUR', #missing r!
  to_currency: 'THB'
}

service.find_exchange_rate(data)


He'll get the rate of exchange. Moreover, it may seem that this rate is a valid value (USD is a bit cheaper than EUR but not enough to be easily noticeable). I don't have to tell what effects this may have!

In this situation, a lot of developers would say: If you had unit tests in your client code you wouldn't have a problem. Maybe we wouldn't have problems, but the world is not perfect, and if you can minimize effects of such errors, you should. Eventually, the API owner is responsible for data correctness, not the client. Usually, it's better to not deliver data at all than to deliver improper data.

More Secure But Still Vulnerable

The approach with fetch  is more secure but this code is not fully secured yet. When I forget to assign a correct value to any of  data  attributes, but all keys are present  nilw will be introduced.

data = {
  value: 1000,
  from_currency: 'EUR',
  to_currency: nil
}

service.find_exchange_rate(data)


Obviously, in order to guarantee everything is okay, we would have to introduce a dedicated validator.

Take a look at an Indigo.Design sample application to learn more about how apps are created with design to code software.

Topics:
ruby ,hash ,secure code

Published at DZone with permission of

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}