干式验证:不区分大小写的“included_in?”验证 Dry::Validation.Schema
dry-validation: Case insensitive `included_in?` validation with Dry::Validation.Schema
我正在尝试为预先确定的有效品牌列表创建验证,作为 ETL 管道的一部分。我的验证要求不区分大小写,因为有些品牌是无意义的复合词或缩写。
我创建了一个自定义谓词,但我不知道如何生成适当的错误消息。
我读了 the error messages doc,但我很难理解:
- 如何为我的自定义谓词构建语法?
- 我可以直接在模式 class 中应用消息,而不引用外部 .yml 文件吗?我看了看here,似乎并没有我希望的那么简单。
下面我给出的代码代表了我使用内置谓词和自定义谓词尝试过的内容,每个都有自己的问题。如果有更好的编写规则的方法来实现相同的目标,我很乐意学习。
require 'dry/validation'
CaseSensitiveSchema = Dry::Validation.Schema do
BRANDS = %w(several hundred valid brands)
# :included_in? from https://dry-rb.org/gems/dry-validation/basics/built-in-predicates/
required(:brand).value(included_in?: BRANDS)
end
CaseInsensitiveSchema = Dry::Validation.Schema do
BRANDS = %w(several hundred valid brands)
configure do
def in_brand_list?(value)
BRANDS.include? value.downcase
end
end
required(:brand).value(:in_brand_list?)
end
# A valid string if case insensitive
valid_product = {brand: 'Valid'}
CaseSensitiveSchema.call(valid_product).errors
# => {:brand=>["must be one of: here, are, some, valid, brands"]} # This message will be ridiculous when the full brand list is applied
CaseInsensitiveSchema.call(valid_product).errors
# => {} # Good!
invalid_product = {brand: 'Junk'}
CaseSensitiveSchema.call(invalid_product).errors
# => {:brand=>["must be one of: several, hundred, valid, brands"]} # Good... (Except this error message will contain the entire brand list!!!)
CaseInsensitiveSchema.call(invalid_product).errors
# => Dry::Validation::MissingMessageError: message for in_brand_list? was not found
# => from .. /gems/2.5.0/gems/dry-validation-0.12.2/lib/dry/validation/message_compiler.rb:116:in `visit_predicate'
引用我的错误消息的正确方法是引用谓词方法。无需担心arg
、value
等
en:
errors:
in_brand_list?: "must be in the master brands list"
另外,通过这样做,我能够在没有单独的 .yml 的情况下加载此错误消息:
CaseInsensitiveSchema = Dry::Validation.Schema do
BRANDS = %w(several hundred valid brands)
configure do
def in_brand_list?(value)
BRANDS.include? value.downcase
end
def self.messages
super.merge({en: {errors: {in_brand_list?: "must be in the master brand list"}}})
end
end
required(:brand).value(:in_brand_list?)
end
我仍然希望看到其他实现,特别是对于通用的不区分大小写的谓词。许多人说 dry-rb
组织得非常好,但我觉得很难理解。
我正在尝试为预先确定的有效品牌列表创建验证,作为 ETL 管道的一部分。我的验证要求不区分大小写,因为有些品牌是无意义的复合词或缩写。
我创建了一个自定义谓词,但我不知道如何生成适当的错误消息。
我读了 the error messages doc,但我很难理解:
- 如何为我的自定义谓词构建语法?
- 我可以直接在模式 class 中应用消息,而不引用外部 .yml 文件吗?我看了看here,似乎并没有我希望的那么简单。
下面我给出的代码代表了我使用内置谓词和自定义谓词尝试过的内容,每个都有自己的问题。如果有更好的编写规则的方法来实现相同的目标,我很乐意学习。
require 'dry/validation'
CaseSensitiveSchema = Dry::Validation.Schema do
BRANDS = %w(several hundred valid brands)
# :included_in? from https://dry-rb.org/gems/dry-validation/basics/built-in-predicates/
required(:brand).value(included_in?: BRANDS)
end
CaseInsensitiveSchema = Dry::Validation.Schema do
BRANDS = %w(several hundred valid brands)
configure do
def in_brand_list?(value)
BRANDS.include? value.downcase
end
end
required(:brand).value(:in_brand_list?)
end
# A valid string if case insensitive
valid_product = {brand: 'Valid'}
CaseSensitiveSchema.call(valid_product).errors
# => {:brand=>["must be one of: here, are, some, valid, brands"]} # This message will be ridiculous when the full brand list is applied
CaseInsensitiveSchema.call(valid_product).errors
# => {} # Good!
invalid_product = {brand: 'Junk'}
CaseSensitiveSchema.call(invalid_product).errors
# => {:brand=>["must be one of: several, hundred, valid, brands"]} # Good... (Except this error message will contain the entire brand list!!!)
CaseInsensitiveSchema.call(invalid_product).errors
# => Dry::Validation::MissingMessageError: message for in_brand_list? was not found
# => from .. /gems/2.5.0/gems/dry-validation-0.12.2/lib/dry/validation/message_compiler.rb:116:in `visit_predicate'
引用我的错误消息的正确方法是引用谓词方法。无需担心arg
、value
等
en:
errors:
in_brand_list?: "must be in the master brands list"
另外,通过这样做,我能够在没有单独的 .yml 的情况下加载此错误消息:
CaseInsensitiveSchema = Dry::Validation.Schema do
BRANDS = %w(several hundred valid brands)
configure do
def in_brand_list?(value)
BRANDS.include? value.downcase
end
def self.messages
super.merge({en: {errors: {in_brand_list?: "must be in the master brand list"}}})
end
end
required(:brand).value(:in_brand_list?)
end
我仍然希望看到其他实现,特别是对于通用的不区分大小写的谓词。许多人说 dry-rb
组织得非常好,但我觉得很难理解。