How to correctly check for nested values in ruby

Viewed 360

I have a ruby hash that looks like this:

payload = {
  "fields" => {
    "publishedDate" => {
      "de"=>"2019-05-02T00:00+02:00"
    }
  }
}

So now I want to access the date. How would I efficiently and correctly write an if statement to check if the date exists?

I'm currently doing something like this but it somehow feels like it is too much code:

payload["fields"] && payload["fields"]["publishedDate"] && payload["fields"]["publishedDate"].first && payload["fields"]["publishedDate"].first.last

Thank you for helping me out!

2 Answers

Assuming the date is always the value (taking the example of de), then you can use dig to reach every publishedDate, then Hash#values to for every hash/value and any?(&:present?) to check if any of the given values is not blank:

(payload.dig('fields', 'publishedDate') || {}).values.any?(&:present?)

In the eventual case that fields and/or publishedDate aren't present in the hash, it'll return nil, and you'll use {} to invoke values, resulting in an empty array with no present? values.

If the hash comes from a request params, you must know that Rails invokes with_indifferent_access on the object and your hash keys are accessible as symbols as well, so you could do:

(payload.dig(:fields, :publishedDate) || {}).values.any?(&:present?)

You can use the values_at method with dig. It will simplify your more advanced need also.

(payload.dig('fields', 'publishedDate') || {}).values_at('de').any?(&:present?)

Through the above solution, you can validate your particular key also. You can also include multiple keys inside your values_at method like

(payload.dig('fields', 'publishedDate') || {}).values_at('de', 'month', 'year').any?(&:present?)
Related