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

Fix guarding rules with nested values specified as a hash #579

Merged
merged 2 commits into from
Aug 14, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions lib/dry/validation/contract.rb
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,10 @@ def inspect
def error?(result, spec)
path = Schema::Path[spec]

if path.multi_value?
solnic marked this conversation as resolved.
Show resolved Hide resolved
return path.expand.any? { |nested_path| error?(result, nested_path) }
end

return true if result.error?(path)

path
Expand Down
12 changes: 12 additions & 0 deletions lib/dry/validation/schema_ext.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,18 @@

module Dry
module Schema
class Path
# @api private
def multi_value?
last.is_a?(Array)
end

# @api private
def expand
to_a[0..-2].product(last).map { |spec| self.class[spec] }
end
end

# @api private
#
# TODO: this should be moved to dry-schema at some point
Expand Down
23 changes: 23 additions & 0 deletions spec/integration/contract/class_interface/rule/nested_data_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,29 @@
end
end

context 'with a rule that depends on two nested values' do
let(:contract_class) do
Class.new(Dry::Validation::Contract) do
params do
required(:event).schema do
required(:active_from).value(:date)
required(:active_until).value(:date)
end
end

rule(event: %i[active_from active_until]) do
key.failure('invalid dates') if value[0] < value[1]
end
end
end

it 'does not execute rule when the schema checks failed' do
result = contract.(event: { active_from: Date.today, active_until: nil })

expect(result.errors.to_h).to eql(event: { active_until: ['must be a date'] })
end
end

context 'with a nested array' do
let(:contract_class) do
Class.new(Dry::Validation::Contract) do
Expand Down