Rails 验证 ASCII 近似值的唯一性

Rails validate uniqueness for the ASCII approximation

希望标题不要太不清楚。

我正在制作一个rails 应用程序,我对rails 验证有疑问。考虑 User,rb 模型文件中的这段代码:

validates :name,
          presence: true,
          length: { maximum: 50 },
          uniqueness: { case_sensitive: false }

我正在使用 friendly_id gem 为用户生成 slug。我不会允许用户更改他们的名字。我现在需要的是确保名称是唯一的,如果两个人在 ascii 近似值中转换了相同的名称,则不会有 UUID 附加到 slugs。

当前行为是:

用户 1 使用名称注册并获得这样的 slug:

name: "Jaiel" slug: "jaiel"

用户 2 现在使用相同的名称但有点不同:

name: "Jàìèl" slug: "jaiel-6558c3f1-e6a1-4199-a53e-4ccc565657d4"

如您所见,这里的问题我想要这样的唯一性验证,即用户 2 会被拒绝,因为这两个名称都会为其 friendly_id 的

生成 slug "jaiel"

非常感谢你在这件事上的帮助

谢谢

看看 ActiveSupport::Inflector.transliterate:

ActiveSupport::Inflector.transliterate('Ærøskøbing')
#=> "AEroskobing"

此外,对于这种类型的验证,您可能希望使用自定义验证(以及您已有的验证):

class User
  validate :unique_slug

  private

  def unique_slug
    names = self.class.all.map(&:asci_name)

    raise ActiveRecord::RecordInvalid.new(self) if names.include?(asci_name)
  end

  def asci_name
    ActiveSupport::Inflector.transliterate(name)
  end
end

显然,在每次验证时查询整个 table 非常低效,但这只是为您指出一个可能的方向。

另一种选择是回调。创建时音译名称:

before_validation: :transliterate_name

def transliterate_name
  self.name = ActiveSupport::Inflector.transliterate(name)
end

它将首先音译名称,然后使用您的验证来验证已音译名称的唯一性。看起来像一个解决方案,绝对没有最初的那么重。