bun*_*ufi 4 ruby validation uuid ruby-on-rails
我正在使用API。为了获得更好的开发人员体验,我想向用户报告任何容易发现的问题params。我的代码验证字符串,整数,布尔值,iso8601日期和特定于域的值列表。我正在研究一种验证字符串是否为有效UUID的方法。我正在研究可能的选择。
小智 6
虽然我的回答会稍微限制问题的一般性,但我希望它仍然足够有趣。此限制是假设您根据要检查的参数集实例化一个新对象,开始验证然后返回错误对象,除非为零。
# params[:lot] = { material_id: [SOME STRING], maybe: more_attributes }
lot = Lot.new params[:lot]
lot.valid?
Run Code Online (Sandbox Code Playgroud)
这样您就可以使用 Rails 的内置验证机制。但是,截至 2020 年 5 月,似乎仍然没有本地支持将属性的格式验证为 UUID。对于原生,我的意思是:
# models/lot.rb
# material_id is of type string, as per db/schema.rb
validates :material_id,
uuid: true
Run Code Online (Sandbox Code Playgroud)
在 Rails 6.0.3 中输入这个会得到:
ArgumentError (Unknown validator: 'UuidValidator')
Run Code Online (Sandbox Code Playgroud)
因此,将属性验证为 UUID 的关键是生成一个 UuidValidator 类并确保 Rails 的内部能够自然地找到并使用它。
受到 coderwall.com 的 Doug Puchalski建议的解决方案的启发,结合Rails API 文档,我想出了这个解决方案:
# lib/uuid_validator.rb
class UuidValidator < ActiveModel::EachValidator
def validate_each(record, attribute, value)
unless value =~ /\A[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}\z/i
msg = options[:message] || "is not a valid UUID"
record.errors.add(attribute, msg)
end
end
end
Run Code Online (Sandbox Code Playgroud)
现在,假设您实例化一个新的 Lot 实例并错误地将一个整数作为外键分配给 material_id:
lot = Lot.new({material_id: 1})
lot.material_id
=> "1" # note the auto type cast based on schema definition
lot.valid?
=> false
lot.errors.messages
=> {:material_id=>["is not a valid UUID"]}
# now, assign a valid uuid to material_id
lot.material_id = SecureRandom.uuid
=> "8c0f2f01-8f8e-4e83-a2a0-f5dd2e63fc33"
lot.valid?
=> true
Run Code Online (Sandbox Code Playgroud)
重要提示:
一旦您将属性的数据类型更改为 uuid,
# db/schema.rb
create_table "lots", id: false, force: :cascade do |t|
#t.string "material_id"
t.uuid "material_id"
end
Run Code Online (Sandbox Code Playgroud)
Rails 6 将自动只接受有效的 uuid 分配给 material_id。当尝试分配除有效 UUID 字符串之外的任何内容时,它会优雅地失败:
lot = Lot.new
# trying to assign an integer...
lot.material_id({material_id: 1})
# results in gracious failure
=> nil
# the same is true for 'nearly valid' UUID strings, note the four last chars
lot.material_id = "44ab2cc4-f9e5-45c9-a08d-de6a98c0xxxx"
=> nil
Run Code Online (Sandbox Code Playgroud)
但是,您仍然会得到正确的验证响应:
lot.valid?
=> false
lot.errors.messages
=> {:material_id=>["is not a valid UUID"]}
Run Code Online (Sandbox Code Playgroud)
根据普遍使用正则表达式的建议:
def validate_uuid_format(uuid)
uuid_regex = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/
return true if uuid_regex.match?(uuid.to_s.downcase)
log_and_raise_error("Given argument is not a valid UUID: '#{format_argument_output(uuid)}'")
end
Run Code Online (Sandbox Code Playgroud)
请注意,这仅检查字符串是否遵循8-4-4-4-12格式,并忽略任何版本检查。
| 归档时间: |
|
| 查看次数: |
4991 次 |
| 最近记录: |