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

如何在dry-validations合约中允许metadata哈希包含任意键值对?

如何在dry-validations合约中允许metadata哈希包含任意键值对?

我完全懂你的困扰——你全局开了config.validate_keys = true来挡掉合约外的非法参数,但又想让metadata这个哈希字段能自由接受任意键值对,不用管里面的键是否被预先定义。之前你尝试自定义类型的思路没问题,但写法上踩了点小坑,所以没达到预期效果。

其实不用折腾全局注册类型这么麻烦,咱们直接在合约里给metadata字段单独配置哈希类型,关掉它的键校验就行:

class MyContract < Dry::Validation::Contract
  config.validate_keys = true

  params do
    required(:allowed_param).value(:string, :filled?)
    # 针对metadata单独关闭内部键校验
    optional(:metadata).value(Dry::Schema::Types::Hash.weak(validate_keys: false))
  end
end

这么写的话,全局的键校验依然生效(比如传了allowed_param和metadata之外的参数会被拒绝),但metadata内部的哈希可以随便塞键值对,不会触发“键不允许”的错误。

如果你的多个合约都要用到这种“允许任意键的哈希”类型,想复用的话,正确的自定义类型写法应该是这样的:

# 创建一个不校验键的哈希约束类型
MetadataHash = Dry::Schema::Types::Hash.weak(validate_keys: false)
Dry::Types.container.register('metadata_hash', MetadataHash)

# 合约里直接引用这个自定义类型
class MyContract < Dry::Validation::Contract
  config.validate_keys = true

  params do
    required(:allowed_param).value(:string, :filled?)
    optional(:metadata).value('metadata_hash')
  end
end

你之前的问题出在误用了constructor,其实根本不需要构造器,直接用weak(validate_keys: false)就能得到一个不校验键的哈希类型,它的类型标识会是<Dry::Types[Constrained<Hash rule=[type?(Hash)] validate_keys=false>],这样就能正常工作了。

另外补充个小细节:weak方法会自动把字符串键转换成符号键(或者反过来?),如果你不想做这种自动转换,只想严格接受哈希类型且不校验键,也可以这么写:

Dry::Schema::Types::Hash(validate_keys: false)

这样就只会接受纯哈希类型,不做键的类型转换,同时允许任意键存在。

内容来源于stack exchange

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.07 07:40:29