Today, one of our experts shares their thoughts on how to pass boolean arguments and assign default values to them. As employees of a top Ruby on Rails development company, our developers deepen and share their expertise daily within the team. We also like to share our knowledge online, which has resulted in this article. Follow our blog for more.
Problem
Imagine you are working with a calculator class that sums processed payment amounts. That's the only thing it does by default.
But what if you also want to include processing payments - and not always by default?
Solution
You can pass an argument to perform processing in several ways — for example, as a function parameter, or a hash argument.
If you're dealing with boolean arguments, you can use one of these strategies for assigning a default value:
a) Keyword arguments - they're available in the Ruby 2.0+ version. Here's an example of a keyword argument:
class Calculator
def initialize(user:, include_processing_payments: true)
@user = user
@include_processing_payments = include_processing_payments
end
end
b) A hash - you typically use a hash to pass multiple arguments or additional values. Here's what it looks like in our example:
class Calculator
def initialize(options)
@user = options[:user]
# the second argument of fetch is going to be the default value
@include_processing_payments = options.fetch(:include_processing_payments, true)
end
end
Now, both solutions might look pretty neat at first glance. But can you be 100% sure they will handle every possible default value?
The strategies will work for cases where you pass true or false; there's no doubt about it.
What about nil?
The first approach I showed you assign the default value to the parameter only when it's not passed. So even if you pass `nil`, you're still not going to get a default value assigned.
The second approach looks promising, but it's not going to work either when you try to pass `nil` in your hash explicitly: `{ include_processing_payments: nil }`.
Is there a way to fix that problem and ensure you get a boolean value assigned correctly?
Consider following two strategies.
Double negation
class Calculator
def initialize(user:, include_processing_payments: true)
@user = user
@include_processing_payments = !!include_processing_payments
end
end
In this solution, you'll be negating the parameter value twice. When you pass a value, you can be sure that it's turned into a true or false.
For example, if you pass a `nil` value, you're going to get a false. And that's what you'll be looking for most of the time.
Compact method
class Calculator
def initialize(options)
@user = options[:user]
@include_processing_payments = options.compact.fetch(:include_processing_payments, true)
end
end
For hash parameters, you can try using a `compact` method. It removes all the key-value pairs where the value is `nil`. This way, the fetch method won't be able to find the required key and so will assign true as the default value.
However, this approach doesn't work for arguments that are not supplied with `nil` or boolean values. To support this kind of case, you'll still need double negation: `!!options.fetch(:include_processing_payments, true)`.
Note: You might spot that type of code snippet in your code:
class Calculator
def initialize(user:, include_processing_payments: true)
@user = user
@include_processing_payments = include_processing_payments || true
end
end
It might look correct initially, but you should avoid that kind of implementation. Sure, it solves your problem with the `nil` value, but it also generates a new issue. The `include_processing_payments` instance variable will always be evaluated as true, even if you pass `false` instead of `nil` as an argument.
Key takeaways
Boolean arguments can be tricky.
That's why you should always take extra care when passing them in your code. Just choose the proper implementation method to avoid problems when assigning default values from boolean arguments .If you are encountering issues, need help in resolving technical issues, or need additional Ruby on Rails experts to team up with your team - contact us.