Handling nested params as an optional value
As noted in this forum discussion, using a nested params object that also allows nil doesn't validate correctly.
inner_schema = Dry::Schema.Params do
required(:path).filled(:string)
end
outer_schema = Dry::Schema.Params do
required(:foo).maybe(inner_schema)
end
outer_schema.("foo" => "").success? #=> false, but should be true
There's various workarounds attempted in that discussion, and one that I've found works for me, plus another good suggestion from @solnic, but it's been acknowledged that this underlying issue should be addressed, hence why I've logged this issue.
It uses to_hash from dry-types. I actually don’t remember why we decided to do this but your usecase clearly shows that it wasn’t a good idea. Using maybe in this case cannot work.
My environment
I don't feel this issue is environment-specific, but just in case the context is useful:
- Affects my production application: YES
- Ruby version: 2.6.6
- OS: macOS (development) and Linux (production)
@timriley @flash-gordon do you guys remember why we decided to make to_hash return an empty hash in case of an empty string?
@solnic no clue, if it was decided at some point I would follow the commits
I think it was to make it in line with how to_array works (which turns empty strings into empty arrays) 🤔
@solnic maybe(:hash) should use Types::Params::Nil | Types::Params::Hash or smth like this, it's Types::Params::Nil's job to coerce to nil, no?
Without digging into our chat history (which I’m willing to try at some point if it will help), I’m pretty sure what @flash-gordon mentioned was right: that we followed what we did for the other “structural” type, i.e. array, and make it so the empty string coerces into the empty representation of that type, because there’s no other way to express an empty array or hash via a simple form post.
Clearly this isn’t working as is for @pat‘s case, but I also wonder: if we changed Types["params.hash"][""] to coerce to nil, would that break another set of uses for which the current behavior seems sensible?
Does @flash-gordon‘s comment just above hint at potential way to fix this while preserving the existing hash coercion?
FWIW I’d be happy to consider changing the behavior if that’s the only way forward. In doing that, however, I think we should probably survey a full range of use cases, maybe also do a review of how Rails (and others) handles posting of nested forms to see if there’s some helpful consistency that can be gained.
@timriley @flash-gordon here's the commit which made to_hash return an empty hash for an empty string
Bless that person for writing such a descriptive commit message!