How to coerce empty string to nil

Hi.
I have an HTML form, thus params sent to server can contain empty strings.
I would like to validate that first or second attribute have to be filled (to do not allow both be empty).
And I cannot find a clear way how to do it.

class Search < Dry::Validation::Contract
  params do
    optional(:name).value(:string)
    optional(:email).value(:string)
  end

  rule(:name, :email) do
    if !key?(:name) && !key?(:email)
      base.failure("name or email have to be filled in")
    end
  end
end

The “key?” method returns true for empty strings. How to treat empty strings as nils?

No need to use a rule, Schemas can do this directly.

params do
  optional(:name).filled(:string)
  optional(:email).filled(:string)
end

Thanks for suggestion, but this doesn’t work for me:

Search.new.call(name: "", email: "")
=> #<Dry::Validation::Result{:name=>"", :email=>""} errors={:name=>["must be filled"], :email=>["must be filled"]}>

I want to allow empty strings in this case and treat them as nils. Here I would expect that only the custom rule would error out.

Sorry, I misunderstood your question. Two things: maybe will coerce your strings to nil, and you want to be checking values in your rule rather than key?

class Search < Dry::Validation::Contract
  params do
    optional(:name).maybe(:string)
    optional(:email).maybe(:string)
  end

  rule :name, :email do
    unless values[:name] || values[:email]
      base.failure("name or email have to be filled in")
    end
  end
end
2 Likes

Yes. This is what I was looking for. Thank you.