Hanami 1.3.3如何实现验证器继承复用公共校验规则
Hanami 1.3.3 验证器公共逻辑复用实现方案
Hanami 1.3.x 版本的 Hanami::Validations 原生没有提供类继承自动合并校验规则的能力,validations 块属于类级别的宏定义,子类默认会覆盖父类的规则块,不需要等待官方的继承实现,以下两种生产环境可用的方案都可以满足DRY要求,消除重复代码。
方案一:公共规则模块注入(推荐,兼容性最好)
通过模块封装所有公共配置和校验规则,用块注入的方式追加各场景专属规则,完全基于框架公开API实现,不受版本小迭代的内部实现变动影响。
首先抽离公共逻辑模块:
module Validators module MyEntities module CommonRules def self.included(base) base.class_eval do include Hanami::Validations::Form include Validatable messages :i18n validations do # 此处放所有公共校验规则,比如你提到的20+条通用规则 required(:first_attr).filled(:bool?) required(:second_attr).filled(:int?) # 注入子类追加的专属规则 instance_exec(&@entity_specific_rules) if instance_variable_defined?(:@entity_specific_rules) end end end # 对外暴露追加专属规则的接口 def self.rules(&block) @entity_specific_rules = block end end end end
重构后的创建、更新验证器代码如下,没有任何重复逻辑:
module Validators module MyEntities class Create include CommonRules rules do required(:attr_for_create).filled(:str?) # 所有创建场景专属规则写在这里 end end end end
module Validators module MyEntities class Update include CommonRules rules do required(:attr_for_update).filled(:str?) # 所有更新场景专属规则写在这里 end end end end
该方案的规则执行顺序和你原有单文件编写的顺序完全一致,i18n错误提示、校验逻辑行为和原实现无差异。
方案二:类继承实现(适合偏好继承写法的场景)
如果更习惯类继承的代码组织方式,可以通过重写类的inherited回调,手动把父类的校验规则复制到子类,实现规则继承。注意该方案会用到框架内部存储规则的实例变量,跨小版本升级时需要做兼容性验证。
首先定义所有验证器的基类:
class ApplicationValidator include Hanami::Validations::Form include Validatable messages :i18n validations do # 此处放所有公共校验规则 required(:first_attr).filled(:bool?) required(:second_attr).filled(:int?) end def self.inherited(subclass) super # 复制父类已定义的校验规则到子类,避免被子类的validations块完全覆盖 subclass.instance_variable_set(:@_validations, @_validations.dup) end end
子类直接继承基类,追加自己的专属规则即可:
module Validators module MyEntities class Create < ApplicationValidator validations do required(:attr_for_create).filled(:str?) end end class Update < ApplicationValidator validations do required(:attr_for_update).filled(:str?) end end end end
注意事项
- 不要直接在父类定义
validations块后让子类无处理继承,子类调用validations方法时会直接清空父类已定义的规则,不会做合并。 - 如果有带参数的复用规则,可以在公共模块/基类里定义可复用的校验方法,在规则块里直接调用即可,进一步减少重复。
- 两种方案都兼容原有的i18n配置,不需要修改现有国际化错误提示文件。
内容的提问来源于stack exchange,提问作者mechnicov
相关产品推荐
相关产品推荐

