dry-rb/dry-validation

Inconsistent behavior in nested schemas via passed in blocks

Open

#703 创建于 2022年1月28日

在 GitHub 查看
 (8 评论) (0 反应) (0 负责人)Ruby (193 fork)github user discovery
bughelp wanted

仓库指标

Star
 (1,421 star)
PR 合并指标
 (PR 指标待抓取)

描述

Describe the bug

When schemas are passed blocks, required field behavior does not always work, and there is inconsistent behavior for reaching validation rules -- although it seems to correlate with whether the required is evaluated.

To Reproduce

class TireSchema < Dry::Schema::JSON
    define do
        optional(:tread).value(:string, included_in?: %w(offroad allterrain sport road))
        optional(:size).value(:integer)
    end
end

class SportsCarSchema < Dry::Schema::JSON
    define do
        optional(:recommended_tire).hash.schema(TireSchema.new) do
            optional(:tread).value(:string, included_in?: %w(sport road))
        end
    end
end

class RaceDriverContract < Dry::Validation::Contract
    rule('car.recommended_tire.size') do
        puts "The runtime made it to the rule!"
    end

    json do
        required(:car).hash.schema(SportsCarSchema.new) do
            required(:recommended_tire).hash.schema(TireSchema.new) do
                required(:size).value(:integer)
            end
        end
    end
end

contract = RaceDriverContract.new

contract.call({ car: { recommended_tire: { tread: "invalid value" } } })
# The runtime made it to the rule!
# => #<Dry::Validation::Result{:car=>{:recommended_tire=>{:tread=>"invalid value"}}} errors={:car=>{:recommended_tire=>{:tread=>["must be one of: offroad, allterrain, sport, road"]}}}>

contract.call({ car: { recommended_tire: { tread: "sport" } } })
# => #<Dry::Validation::Result{:car=>{:recommended_tire=>{:tread=>"sport"}}} errors={:car=>{:recommended_tire=>{:size=>["is missing"]}}}>

contract.call({ car: { recommended_tire: { tread: "allterrain" } } })
# The runtime made it to the rule!
# => #<Dry::Validation::Result{:car=>{:recommended_tire=>{:tread=>"allterrain"}}} errors={:car=>{:recommended_tire=>{:tread=>["must be one of: sport, road"]}}}>

Expected behavior

I would expect every one of the above results to contain {:recommended_tire=>{:size=>["is missing"]}, and I would either expect all of them to make it to the rule or none of them to make it to the rule.

My environment

  • Affects my production application: YES
  • Ruby version: 2.7.2
  • OS: macOS 12.0.1 21A559

贡献者指南