[dry-validation] how to write rules for nested array of hashes

How does one apply rules to nested arrays of hashes? Toy example:

class MyContract < Dry::Validation::Contract
  schema do
    required(:stores).array(:hash) do
      required(:products).array(:hash) do
        required(:name).filled(:string)
      end
    end
  end
end

What is the right way to apply validation to all the product names (specifically, stores[i][:products][j][:name])? The only thing I can come up with uses nested loops and is really ugly.

Basically, my goal would be something like this:

rule("stores.products.name") do
  key.failure("is not valid") unless validate(name)
end

You can write your rule as follows:

rule(:stores).each do
    value[:products].each_with_index do |product, index|
      name_key = key(key.path.keys + [:product, index])
      name_key.failure('must have a name') unless validate(product[:name])
    end
  end

Hope it helps

1 Like

I tried something like that, but tbh it feels like a hack. And I actually have a more deeply nested structure I need to validate. For example:

class MyContract < Dry::Validation::Contract
  schema do
    required(:stores).array(:hash) do
      required(:products).array(:hash) do
        required(:sizes).array(:hash) do
          required(:text).filled(:integer)
        end
      end
    end
  end
end

With something like this, I think Iā€™d need nested loops in the rule, which starts to get tedious.

This is not yet supported by each but the goal is to eventually be able to write something like rule("stores[].products[].sizes[]").each { .... } that would trigger the rule for each element in the sizes array that passed schema checks.

Wow, that would be great syntax! Looking forward to it. Thanks for the info.

1 Like