Rails 7中dry-validation验证异常求助:参数缺失报错、存在时验证失效
dry-validation在Rails 7中的验证异常解决
问题重现
在Rails 7应用的MandateController#create方法中使用dry-validation 1.10.0验证JSON请求,遇到以下异常:
- 当顶层参数
sdd_setup_request缺失时,验证正常报错; - 将
sdd_setup_request改为optional后,即使请求中存在该参数但缺少内部的return_url,验证仍直接通过,未触发预期的缺失错误。
相关代码
请求结构:
{ "sdd_setup_request": { "return_url": "https://example.com/return", "data": { (...) } } }
验证器类:
class SddRequestValidator < ApplicationService params do # 最初用required,改为optional后出现问题 optional(:sdd_setup_request).schema do required(:return_url).value(:string) required(:data).hash do (...) end end end end
控制器代码:
class MandatesController < BaseController def create result = SddRequestValidator.call(params) if result.success? (...) else render_error(result.errors.to_h, status: :bad_request) end end end
补充配置:
- 初始化文件
initializers/dry_validator.rb:
require 'dry/validation' Dry::Validation.load_extensions(:monads)
- 父类
ApplicationService:
class ApplicationService < Dry::Validation::Contract def self.call(*args) new.call(*args) end end
问题原因
- Rails参数对象的特殊处理:Rails的
params是ActionController::Parameters对象,并非普通Ruby哈希。dry-validation在处理该对象时,无法正确识别嵌套字段的缺失情况,导致嵌套验证规则未被执行。 - dry-validation的
optional规则逻辑:当字段标记为optional时,只有字段存在且非空时才会触发嵌套schema验证;但ActionController::Parameters可能被误判为“符合要求”,跳过内部验证。
解决方案
1. 将Rails参数转换为普通哈希
在控制器中调用验证器时,把params转为普通哈希,确保dry-validation能正确解析嵌套结构:
class MandatesController < BaseController def create # 替换params为params.to_h result = SddRequestValidator.call(params.to_h) if result.success? (...) else render_error(result.errors.to_h, status: :bad_request) end end end
2. 强化验证器规则严谨性
如果需要sdd_setup_request存在时必须是完整结构,可添加filled约束,避免空值绕过验证:
class SddRequestValidator < ApplicationService params do optional(:sdd_setup_request).filled.schema do required(:return_url).value(:string) required(:data).hash do (...) end end end end
3. 确认请求解析正确性
确保前端发送请求时设置Content-Type: application/json,避免Rails将JSON请求解析为普通表单参数,导致嵌套结构丢失。
内容的提问来源于stack exchange,提问作者mr_muscle
相关产品推荐
相关产品推荐

