Welcome! There isn’t a lot of documentation specific to Rails because Dry-rb is a toolkit intended for all Ruby code. There are a handful of specific Rails integrations provided by dry-rails but those are simply providing a convention for you to follow, it isn’t anything you couldn’t write yourself with only a little effort.
Schema Processor Types
The difference between
json in your example relates to the schema processor. Ultimately, this mostly just changes the default dry-types that are used.
Schemas in dry-schema process keys in a series of steps:
- Key Validation: is a required key missing
- Key Coercion: transform a string key to symbol
- Value Filter: screen out values before they are coerced
- Value Coercion: apply any transformations defined in the type spec
- Value Type: does the value pass the type spec
- Value predicate: does the predicate (if defined) return true
Validation contracts tack on a final pass, applying rules to the entire schema that can encompass multiple keys.
The reason for
json processor types comes from the different coercion rules you want to apply depending on whether you are dealing with HTTP params or JSON data.
For instance, it’s commonplace to see empty string returned in HTTP params that
params automatically transforms to
nil. That doesn’t happen with
json. Likewise, JSON defines boolean types so those are not coerced, but HTTP params need to transform string values into booleans. Different rules for different use-cases.
The distinction between
maybe are different macro types.
filled is just a special-case macro for a very common thing you want to do: declare a type but ensure it’s non-empty. I believe I remember reading somewhere this is deprecated, so I would recommend using the predicate instead.
value is the primary macro for a value. It applies the type spec to the value to ensure its correctness, and coerce it if desired.
value(:string) is just a shorthand for
A macro can apply two rules to a value:
- type spec
Predicates come from dry-logic and as you might suspect, they are just predicate methods that answer a question about an object.
filled macro is doing two things: a type spec, and a predicate.
So that will ensure that the value is a string, and it is non-empty.
The filled predicate may also be built into the type spec as a constraint using the same logic operation
Types = Dry.Types(default: :strict)
FilledString = String.constrained(filled: true)
class NewUserContract < Dry::Validation::Contract