如何在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
相关产品推荐
相关产品推荐

