I’m working on switching a project from ActiveRecord validations to dry-validations. Some of the ActiveRecord models are in a Rails engine and re-opened in a Rails application to add additional validations. In the short term I’d like to mimic this.
# in the engine
class Form < Dry::Struct
def schema
@schema ||= Dry::Validation.Params do
required(:short_title).filled
end
end
end
In essence I want to take the original schema and extend it.
My guess is that it that the schema object is frozen so it isn’t directly possible. So my first idea was composition:
# in the app, re-opening the class and adding more validations
class Form
def schema
@schema ||= Dry::Validation.Params do
schema { super } # merge original validations
required(:email).filled # add new validation
end
end
end
However I’m monkey patching so I can’t call super
. Even so it does not seem to work:
v1 = Dry::Validation.Params { required(:name).filled }
v2 = Dry::Validation.Params { schema { v1 } }
v2.call(name: nil).errors # => {}
Any pointers/thought would be appreciated.
I can get some of the way with:
class V1 < Dry::Validation::Schema
define! { required(:short_title).filled }
end
V2 = Dry::Validation.Params(V1) { required(:email).filled }
But that means I have to define the schema in two different ways.
And also using inheritance:
class V1 < Dry::Validation::Schema
define! { required(:short_title).filled }
end
class V2 < V1
define! { required(:email).filled }
end
There are several ways to inherit schema without necessarily writing the class.
The key to the first one is the build
option in the Dry::Validation.Schema
method:
S1 = Dry::Validation.Schema(build: false) do
required(:name).filled
end
S2 = Dry::Validation.Params(S1) do
required(:age).filled(:int?, gt?: 0)
end
Be warned, however, that S1
in this case would be the class of the schema, not the schema itself. So instead of doing this:
S1.({name: 'William'})
You will have to do this:
S1.new.({name: 'William'})
The second option is just use the parent schema’s class in the child schema:
S1 = Dry::Validation.Schema do
required(:name).filled
end
S2 = Dry::Validation.Params(S1.class) do
required(:age).filled(:int?, gt?: 0)
end
1 Like
Is there a way to extend more than one schema?