dry-schema icon indicating copy to clipboard operation
dry-schema copied to clipboard

Handling nested params as an optional value

Open pat opened this issue 5 years ago • 8 comments

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)

pat avatar Jun 16 '20 10:06 pat

@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 avatar Jun 16 '20 10:06 solnic

@solnic no clue, if it was decided at some point I would follow the commits

flash-gordon avatar Jun 16 '20 10:06 flash-gordon

I think it was to make it in line with how to_array works (which turns empty strings into empty arrays) 🤔

solnic avatar Jun 16 '20 10:06 solnic

@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?

flash-gordon avatar Jun 16 '20 10:06 flash-gordon

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?

timriley avatar Jun 16 '20 11:06 timriley

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 avatar Jun 16 '20 11:06 timriley

@timriley @flash-gordon here's the commit which made to_hash return an empty hash for an empty string

solnic avatar Jun 17 '20 04:06 solnic

Bless that person for writing such a descriptive commit message!

timriley avatar Jun 17 '20 04:06 timriley