I have Hanami 1.3.3 and two validators there: for create and update actions like these
module Validators
module MyEntities
class Create
include Hanami::Validations::Form
include Validatable
messages :i18n
validations do
required(:first_attr).filled(:bool?)
required(:second_attr).filled(:int?)
required(:attr_for_create).filled(:str?)
end
end
end
end
module Validators
module MyEntities
class Update
include Hanami::Validations::Form
include Validatable
messages :i18n
validations do
required(:first_attr).filled(:bool?)
required(:second_attr).filled(:int?)
required(:attr_for_update).filled(:str?)
end
end
end
end
In fact, the number of validation rules is more than twenty
As you see there is a lot of repetitive code here
I want to DRY it and use some inheritance
I couldn't find some receipts for this. Just discussion in GitHub issue. Outcome of that discussion: it's very tricky
How to use inherited validators in Hanami?
CodePudding user response:
To answer this question, we need to look at the source code of the library
As you see there is a validations
method in Hanami validations gem
This method builds schema for validation. Among other things, the block passed to this method is used. It is the block with those validations rules that we write in our validators inside the application
To use inheritance, we can overwrite validations
method in the parent class and join two blocks there: basic parent rules and child rules
To do this, we need instance_eval
method
module Validators
module MyEntities
class Base
include Hanami::Validations::Form
include Validatable
messages :i18n
class << self
def validations(&rules)
schema_predicates = __predicates
base = _build(predicates: schema_predicates, &_base_rules)
schema = _build(predicates: schema_predicates, rules: base.rules, &my_entity_rules(&rules)) # overwrite just here
schema.configure(&_schema_config)
schema.configure(&_schema_predicates)
schema.extend(__messages) unless _predicates.empty?
self.schema = schema.new
end
private
def my_entity_rules(&rules)
Proc.new do
instance_eval(&rules) # use child rules
required(:first_attr).filled(:bool?)
required(:second_attr).filled(:int?)
end
end
end
end
end
end
module Validators
module MyEntities
class Create < Base
validations do
required(:attr_for_create).filled(:str?)
end
end
end
end
module Validators
module MyEntities
class Update < Base
validations do
required(:attr_for_update).filled(:str?)
end
end
end
end