Hi folks,
I’m using dry-schema with some form data, and my understanding is that empty string values in a params schema are treated as nil. But I’m finding that if the attribute value is optional and expected to be matched against a nested schema, empty string values are still validated against the nested schema.
Here’s an initial attempt:
inner_schema = Dry::Schema.Params do
required(:path).filled(:string)
end
outer_schema = Dry::Schema.Params do
required(:foo).maybe(inner_schema)
end
I’d expect the first three of these test cases to pass, and the last one to fail, but the first one actually fails as well because the path
value is missing:
outer_schema.("foo" => "").success? #=> false, but we want it to be true
outer_schema.("foo" => nil).success? #=> true
outer_schema.("foo" => {"path" => "bar"}).success? #=> true
outer_schema.("foo" => {"other" => "bar"}).success? #=> false
I feel like it’s doing the validation before it realises the empty string is the equivalent of nil for params? I’ve tried a few other variations, but none work to what I need:
# explicit inner schema rather than something reusable
# fails the first test case
outer_schema = Dry::Schema.Params do
required(:foo).maybe(:hash) do
required(:path).filled(:string)
end
end
outer_schema.("foo" => "")
# => #<Dry::Schema::Result{:foo=>{}} errors={:foo=>{:path=>["is missing"]}}>
# explicit empty comparison fails third test case, because
# it seems to require symbol keys - surprising for a Params schema?
outer_schema = Dry::Schema.Params do
required(:foo).maybe do
empty?.or(inner_schema)
end
end
outer_schema.("foo" => {"path" => "bar"})
# => #<Dry::Schema::Result{:foo=>{"path"=>"bar"}} errors={:foo=>{:path=>["is missing"]}}>
outer_schema.("foo" => {:path => "bar"}).success? # => true
# wrap the schema in a hash() call, and it doesn't care about the inner values
# at all, so even what should be *invalid* is considered valid.
outer_schema = Dry::Schema.Params do
required(:foo).maybe do
empty?.or(hash(inner_schema))
end
end
outer_schema.("foo" => {"other" => "bar"})
# => #<Dry::Schema::Result{:foo=>{}} errors={}>
I’m not sure if any of these approaches should actually be working and thus I’ve found a bug, or if I’m trying to do something that isn’t technically possible. Any guidance would be greatly appreciated