Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rule validation does not show in errors when the key validated is in an array of hashes #722

Open
tanyongkee opened this issue Dec 1, 2022 · 1 comment

Comments

@tanyongkee
Copy link

Describe the bug

Rule validation does not show in errors when the key validated is in an array of hashes

To Reproduce

Provide detailed steps to reproduce, an executable script would be best.

  1. Define the contract
#address_contract.rb
class AddressContract < Dry::Validation::Contract
  json do
    required(:street_address).filled(:string)
    required(:country).filled(:string)
  end
end
  1. define another contract that uses AddressContract
#new_user_contract.rb
class NewUserContract < Dry::Validation::Contract
  json do
    required(:user_details).array(:hash) do
      required(:email).filled(:string)
      required(:address).hash(AddressContract.schema)
    end
  end

  rule(:user_details).each do
    unless /\A[\w+\-.]+@[a-z\d\-]+(\.[a-z\d\-]+)*\.[a-z]+\z/i.match?(value[:email])
      key.failure('has invalid format')
    end
  end
end
  1. Create the contract
contract = NewUserContract.new
  1. Validate the following payload
payload = {
   user_details: [{email: 'jane', address: '17'}]
 }
 
 contract.call(payload)

Expected behavior

expected output

> #<Dry::Validation::Result{:user_details=>[{:email=>"jane", :address=>"17"}]} errors={:user_details=>{0=>{:email=>["has invalid format"], :addresss=>["must be a hash"]}}}>

but got

> #<Dry::Validation::Result{:user_details=>[{:email=>"jane", :address=>"17"}]} errors={:user_details=>{0=>{:address=>["must be a hash"]}}}>

As you can see, it is missing the rule validation for the format of the email. Is this a bug? Or am I missing something here?

My environment

  • Affects my production application: YES/NO
  • Ruby version: 3.1.2
  • OS: MacOS M1
@esparta
Copy link
Contributor

esparta commented Dec 7, 2022

I think we have something here and it's a little bit subtle under the evaluation of rules. For example, if we make the address field missing a field, the error is also not accurate:

# frozen_string_literal: true

require 'bundler/inline'

gemfile do
  source 'https://rubygems.org'

  gem 'dry-validation'
  gem 'rspec'
  gem 'warning'
  gem 'i18n'
end

require 'rspec/autorun'

AddressContract = Dry::Schema.JSON do
  required(:street_address).filled(:string)
  required(:country).filled(:string)
end

class UserContract < Dry::Validation::Contract
  json do
    required(:user_details).array(:hash) do
      required(:address).hash(AddressContract)
      required(:email).filled(:string)
    end
  end

  rule(:user_details).each do |index:|
    key(
      [:user_details, index, :email]
    ).failure('has invalid format') unless value[:email].include?('@')
  end
end

RSpec.describe UserContract do
  let(:payload) do
    {
      user_details: [{email: 'jane', address: { country: 'UK' }]
    }
  end

  subject(:contract) do
    described_class.new.call(payload)
  end

  it do
    expect(contract.errors.to_h).to match(
      {
        user_details: {
          0 => {
            email: ['has invalid format'],
            address: { street_address: ['is missing'] }
          }
        }
      }
    )
  end
end

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants