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

schemas with dry-logic operators API fail when dry/validators rule is added

Open idoa01 opened this issue 4 years ago • 4 comments

Following issue #245, I tried to implement a similar situation inside a dry-validators contract, but the following code fails when there is at least one rule involved, see example below

require 'dry/validation'

HomeAddress = Dry::Schema.JSON do
  required(:id).filled(:string)
  required(:address).filled(:string)
end

WorkAddress = Dry::Schema.JSON do
  required(:id).filled(:string)
  required(:company).filled(:string)
end

class NewUserContract < Dry::Validation::Contract
  json do
    required(:first_name).filled(:string)
    required(:last_name).filled(:string)
    required(:email).filled(:string)
    required(:addresses).array(:hash, HomeAddress | WorkAddress)
  end

  rule(:first_name) do
    key.failure('should be John') unless value == 'John'
  end
end

valid_hash = {
  'first_name' => 'foo',
  'last_name' => 'baz',
  'email' => '[email protected]',
  'addresses' => [
    { 'address' => 'blah' }, # doesn't include 'id' like it should
    { 'id' => 'work', 'company' => 'blah.com' }
  ]
}

contract = NewUserContract.new
result = contract.call(valid_hash)

puts result.errors.to_h.inspect

which crashes with the following stacktrace:

Traceback (most recent call last):
	14: from schema.rb:37:in `<main>'
	13: from /Users/ido/.rvm/gems/ruby-2.7.0@schema-test/gems/dry-validation-1.5.0/lib/dry/validation/contract.rb:94:in `call'
	12: from /Users/ido/.rvm/gems/ruby-2.7.0@schema-test/gems/dry-validation-1.5.0/lib/dry/validation/result.rb:25:in `new'
	11: from /Users/ido/.rvm/gems/ruby-2.7.0@schema-test/gems/dry-validation-1.5.0/lib/dry/validation/contract.rb:95:in `block in call'
	10: from /Users/ido/.rvm/gems/ruby-2.7.0@schema-test/gems/dry-validation-1.5.0/lib/dry/validation/contract.rb:95:in `each'
	 9: from /Users/ido/.rvm/gems/ruby-2.7.0@schema-test/gems/dry-validation-1.5.0/lib/dry/validation/contract.rb:96:in `block (2 levels) in call'
	 8: from /Users/ido/.rvm/gems/ruby-2.7.0@schema-test/gems/dry-validation-1.5.0/lib/dry/validation/contract.rb:96:in `any?'
	 7: from /Users/ido/.rvm/gems/ruby-2.7.0@schema-test/gems/dry-validation-1.5.0/lib/dry/validation/contract.rb:96:in `block (3 levels) in call'
	 6: from /Users/ido/.rvm/gems/ruby-2.7.0@schema-test/gems/dry-validation-1.5.0/lib/dry/validation/contract.rb:126:in `error?'
	 5: from /Users/ido/.rvm/gems/ruby-2.7.0@schema-test/gems/dry-validation-1.5.0/lib/dry/validation/result.rb:106:in `error?'
	 4: from /Users/ido/.rvm/gems/ruby-2.7.0@schema-test/gems/dry-schema-1.5.0/lib/dry/schema/result.rb:115:in `error?'
	 3: from /Users/ido/.rvm/gems/ruby-2.7.0@schema-test/gems/dry-schema-1.5.0/lib/dry/schema/result.rb:115:in `any?'
	 2: from /Users/ido/.rvm/gems/ruby-2.7.0@schema-test/gems/dry-schema-1.5.0/lib/dry/schema/message_set.rb:51:in `each'
	 1: from /Users/ido/.rvm/gems/ruby-2.7.0@schema-test/gems/dry-schema-1.5.0/lib/dry/schema/message_set.rb:51:in `each'
/Users/ido/.rvm/gems/ruby-2.7.0@schema-test/gems/dry-schema-1.5.0/lib/dry/schema/result.rb:115:in `block in error?': undefined method `path' for #<Dry::Schema::Message::Or::MultiPath:0x00007f97880db7a0> (NoMethodError)

Expected behavior not to fail , produce the following output (like it does if the rule(:first_name) doesn't exist)

{:addresses=>{0=>{:or=>[{:id=>["is missing"]}, {:id=>["is missing"], :company=>["is missing"]}]}}}

Your environment

  • Affects my production application: YES
  • Ruby version: 2.7
  • dry-rb version: 1.5.0
  • OS: macOS 10.15.3

idoa01 avatar Mar 28 '20 22:03 idoa01

thanks for spotting this and reporting, it'll be fixed in 1.5.1

solnic avatar Mar 31 '20 11:03 solnic

can you suggest a workaround for this issue?

idoa01 avatar Jun 29 '20 08:06 idoa01

@idoa01 yes, you can monkey-patch it like that:

class Dry::Schema::Message::Or::MultiPath
  def path
    []
  end
end

this should make it work

solnic avatar Jul 09 '20 09:07 solnic

will pick this one up

sirfilip avatar Nov 10 '20 22:11 sirfilip