Is there built in support in rails for the default value substitution idiom?

Viewed 7932

I often write code to provide a default value upon encountering nil/empty value.

E.g:

category = order.category || "Any"
#  OR
category = order.category.empty? ? "Any" : order.category

I am about to extend the try method to handle this idiom.

category = order.try(:category, :on_nill => "Any")
#  OR
category = order.try(:category, :on_empty=> "Any")

I am wondering if Rails/Ruby has some method to handle this idiom?

Note:

I am trying to eliminate repetition of || / or / ? operator based idioms.

Essentially I am looking for a equivalent of try method for handling default substitution scenarios.

Without try method:

product_id = user.orders.first.product_id unless user.orders.first.nil? 

With try method:

product_id = user.orders.first.try(:product_id)

It is easy to implement a generic approach to handle this idiom, but I want to make sure I do not reinvent the wheel.

4 Answers

See this question. ActiveSupport adds a presence method to all objects that returns its receiver if present? (the opposite of blank?), and nil otherwise.

Example:

host = config[:host].presence || 'localhost'

fetch will work in the case that you are looking for values by index values of an array or by keys in a hash ( or ActionController::Parameters aka params ). Otherwise, you will have to use the ||= or attempted_value || default_value as described in the other answers.

The current accepted answer's example is rewritten here:

assuming: config = { my_host_ip: '0.0.0.0' }

 config.fetch(:my_host_ip, 'localhost')
 # => "0.0.0.0" 

 config.fetch(:host, 'localhost')
 # => "localhost"

 a_thru_j = ('a'..'j').to_a
 # => ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j"]

 a_thru_j.fetch(1, 'not here')
 # => "b"

 a_thru_j.fetch(10, 'not here')
 # => "not here"
 

Note: without the default, you will raise an error when the key/index is not present:

 config.fetch(:host)
 # => KeyError: key not found: :host

 params.fetch(:host)
 # => ActionController::ParameterMissing: param is missing or the value is empty: host

 a_thru_j.fetch(10)
 # => index 10 outside of array bounds: -10...10
Related