You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.30 11:18:36