Hi! I’m upgrading dry-validation and dry-types in a project to 1.0 (and dry-struct to 1.1) and I’m having trouble figuring out how to migrate code like this:
Dry::Validation.Params do
optional(:foo).maybe(:hash?) do
schema do
optional(:bar).maybe(:bool?)
optional(:baz).maybe(:bool?)
optional(:qux).maybe(:str?)
rule(bar: [:baz, :qux]) do |baz, qux|
baz.true?.then(qux.filled?)
end
end
end
end
I can migrate the schema to Dry::Struct.Params and other code but the rules seem to be problematic since dry-struct doesn’t support them. I’ve tried to use a contract instead but I don’t see any way to have dependencies on the hash keys like the code above (where bar, baz and qux are keys on the foo hash, and their rules depend on each other).
Is this type of thing not supported out-of-the-box anymore? If so, what would be the most “dry” way to achieve it?
Thanks for any help, and thanks for the great gems!
It would seem that this feature has been removed, but I’d still like to know if there is any workaround. My only solution right now is to define the rule on the parent with fairly complex logic to reproduce the original messages with key.failure, etc.
require "dry/validation"
class Contract < Dry::Validation::Contract
params do
optional(:foo) do
nil?.or(
hash do
optional(:bar).maybe(:bool)
optional(:baz).maybe(:bool)
optional(:qux).maybe(:string)
end
)
end
end
rule(foo: [:baz, :qux]) do
if values[:foo]
baz, qux = value
if baz && (qux.nil? || qux.empty?)
key("foo.bar").failure("qux must be filled when baz is true")
end
end
end
end
contract = Contract.new
puts contract.(foo: nil).errors.to_h.inspect
# {}
puts contract.(foo: { bar: true, baz: true, qux: "" }).errors.to_h.inspect
# {:foo=>{:bar=>["qux must be filled when baz is true"]}}
Unfortunately, maybe(:hash) do ... end doesn’t work yet, that’s why you need this nil?.or(hash do...end) thingie for the time being. I just reported an issue about this.