在ruby/rails中验证UUID字符串

6vl6ewon  于 2022-11-04  发布在  Ruby
关注(0)|答案(5)|浏览(189)

我正在开发一个API。为了更好的开发者体验,我想向用户报告params的任何容易发现的问题。我的代码验证字符串、整数、布尔值、iso8601日期和域特定的值列表。我正在寻找一种方法来验证字符串是否是有效的UUID。我正在寻找可能的选项来完成它。

p8h8hvxi

p8h8hvxi1#

基于使用regex的普遍建议:

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

请注意,这只检查字符串是否符合8-4-4-4-12,并忽略任何版本检查。

0vvn1miw

0vvn1miw2#

虽然我的回答会稍微限制问题的概括性,但我希望它仍然足够有趣。这种限制是假设您根据您想要检查的参数集示例化一个新对象,开始验证,然后返回errors对象,除非nil。


# params[:lot] = { material_id: [SOME STRING], maybe: more_attributes }

lot = Lot.new params[:lot]
lot.valid?

这样你就可以使用Rails内置的验证机制。然而,截至2020年5月,似乎还没有原生支持将属性的格式验证为UUID。我所说的原生,是指沿着这样的东西:


# models/lot.rb

# material_id is of type string, as per db/schema.rb

validates :material_id,
  uuid: true

在Rails 6.0.3中键入以下代码,您将得到:

ArgumentError (Unknown validator: 'UuidValidator')

因此,将属性验证为UUID的关键是生成一个UuidValidator类,并确保Rails的内部能够自然地找到并使用它。
受www.example.com的Doug Puchalski提供的coderwall.comsuggested解决方案的启发,结合Rails API docs,我提出了以下解决方案:


# 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

现在,假设您示例化了一个新的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

重要提示

一旦将属性的数据类型更改为uuid,


# db/schema.rb

create_table "lots", id: false, force: :cascade do |t|
  #t.string "material_id"
  t.uuid "material_id"
end

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

但是,您仍然会得到正确的验证响应:

lot.valid?
=> false
lot.errors.messages
=> {:material_id=>["is not a valid UUID"]}
dluptydi

dluptydi3#

您可以使用gem uuidUUID.validate(my_string)类方法。
请访问https://www.rubydoc.info/gems/uuid/2.3.1/UUID#validate-class_method
请注意,它与几种UUID格式匹配。

xfb7svmp

xfb7svmp4#

使用https://github.com/dpep/rspec-uuid

gem 'rspec-uuid'

然后测试它是否为uuid:

it { expect(user_uuid).to be_a_uuid }

或者,您可以检查特定的UUID版本:

it { expect(user_uuid).to be_a_uuid(version: 4) }
js4nwp54

js4nwp545#

使用正则表达式匹配器来验证它,这取决于您验证UUID版本。我相信有很多资源可以用于每个UUID版本的正则表达式模式。

相关问题