dry-schema
dry-schema copied to clipboard
schemas with dry-logic operators API fail when dry/validators rule is added
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
thanks for spotting this and reporting, it'll be fixed in 1.5.1
can you suggest a workaround for this issue?
@idoa01 yes, you can monkey-patch it like that:
class Dry::Schema::Message::Or::MultiPath
def path
[]
end
end
this should make it work
will pick this one up