Maybe means not blank?


#1

required(:answer).maybe seems to check answer is nil, or filled.

It disallows blank…

I was a bit tripped up over this.
Is it by design?


#2

I does allow blank strings when you use Schema.Form, or use a type which coerces empty strings to nils. I deliberately did it like that to remove implicit behaviors because there’s no place for implicit behaviors when it comes to coercion and validation. This is documented btw, but I guess it’s not visible enough in the docs.


#3

I guess I had trouble trying to boil down my problem to a sensible question! Yes I understand about Form, which I’m using…

Can you help explain this array handling?

[8] pry(main)> s = Dry::Validation.Form { required(:options).maybe }; nil
=> nil
[9] pry(main)> s.(options: [])
=> #<Dry::Validation::Result output={:options=>[]} errors={:options=>["must be filled"]}>

It allows (no error) with a blank string:

[10] pry(main)> s.(options: '')
=> #<Dry::Validation::Result output={:options=>nil} errors={}>

Or a filled in array:

[11] pry(main)> s.(options: ['one'])
=> #<Dry::Validation::Result output={:options=>["one"]} errors={}>

Or a nil (as expected with the maybe):

[12] pry(main)> s.(options: nil)
=> #<Dry::Validation::Result output={:options=>nil} errors={}>

I can get around it with:

s = Dry::Validation.Form { required(:options) { filled? | empty? } }

but it seems like the fact it’s a “Form” should allow the empty Array?


#4

Also found specifying the type allows empty array:

Dry::Validation.Form { require(:options).maybe(:array?) }

My problem is really that I don’t want any validation on “options” except when inside a custom rule.

However, if i do this:

[37] pry(main)> s = Dry::Validation.Form { required(:options) }; nil
=> nil
[38] pry(main)> s.({}).success?
=> true

Then it doesn’t seem to be verifying anything… which would be ok, but! I see that my higher level rule doesn’t fire as if the :options rule didn’t fire. Here’s the actual rule I have:

rule(answer: [:answer, :kind, :optional, :options]) do |answer, kind, optional, options|
  (optional.false? > answer.filled?) &
    ((answer.filled? & kind.eql?('number')) > answer.number?) &

    # Only in this "then" do I want to validation options is filled
    ((answer.filled? & kind.eql?('options')) > (
      options.filled? & answer.included_in?(value(:options))
    ))
end

#5

Can you help explain this array handling?

It works like that because maybe is for accepting nils, we probably should not add special cases depending on a schema type as this would only make things more complicated. If you have a case where an empty can be passed in, just use required(:options).value(:array?).

Also found specifying the type allows empty array

Yes, because the way you specify it means it can be nil or an array (doesn’t matter if filled or not).

s = Dry::Validation.Form { required(:options) }

This doesn’t work, you need to specify rules for the value too. It’ll be improved in 1.0.0.


#6

This cleared it up for me:

It shows that if you use “required(:options).maybe” then you are in fact using a ‘default’ right-hand side of :filled?. That means the maybe is saying:

 "You can have null, or if you give a value, it must be filled".

That’s the thing that tripped me up I reported originally! It’s a bit more confusing since the default ‘filled?’ is just that – it’s removed if you provide anything else, like “required(:options).maybe(:array?)”.

I think you were explaining things perfectly, but it didn’t reach me – maybe I didn’t get clear on how the ‘filled?’ was coming into play.

This would be good to have in the docs. I’ll try and send a PR later.