class Dry::Validation::Contract

Contract objects apply rules to input

A contract consists of a schema and rules. The schema is applied to the input before rules are applied, this way you can be sure that your rules won’t be applied to values that didn’t pass schema checks.

It’s up to you how exactly you’re going to separate schema checks from your rules.

@example

class NewUserContract < Dry::Validation::Contract
  params do
    required(:email).filled(:string)
    required(:age).filled(:integer)
    optional(:login).maybe(:string, :filled?)
    optional(:password).maybe(:string, min_size?: 10)
    optional(:password_confirmation).maybe(:string)
  end

  rule(:password) do
    key.failure('is required') if values[:login] && !values[:password]
  end

  rule(:age) do
    key.failure('must be greater or equal 18') if values[:age] < 18
  end
end

new_user_contract = NewUserContract.new
new_user_contract.call(email: 'jane@doe.org', age: 21)

@api public

Extension to use dry-logic predicates as macros.

@see Dry::Validation::PredicateRegistry::WHITELIST Available predicates

@example

Dry::Validation.load_extensions(:predicates_as_macros)

class ApplicationContract < Dry::Validation::Contract
  import_predicates_as_macros
end

class AgeContract < ApplicationContract
  schema do
    required(:age).filled(:integer)
  end

  rule(:age).validate(gteq?: 18)
end

AgeContract.new.(age: 17).errors.first.text
# => 'must be greater than or equal to 18'

@api public