如何避免rails“显示”路线中的序数、整数路线(增量ID)?

use*_*745 1 ruby-on-rails rails-routing

最简单的 MRE 是rails g scaffold users

当我们创建用户时,他们的 id 将为 1、2、3、4 等,他们的“显示”路线将为/show/:id

有时我们不希望网站的用户确切地知道我们有多少用户 - 有没有一种简单的方法来混淆这一点?

我可以想出一种手动执行此操作的方法,方法是在注册时添加一个附加列,其中包含随机 12 位整数,同时还要检查随机生成的整数是否尚不存在。

但我想知道有没有更聪明的方法?

笔记

  • 一个例子:https ://www.youtube.com/watch?v=Gzj723LkRJY (其中Gzj723LkRJY可能是随机生成的并且不可预测)

  • 为什么增量 id 可能不是一个好主意的示例(从 2m 52s 开始大约需要 30 秒)

    许多设计糟糕的网站都使用增量计数器。它可能会告诉你的竞争对手你有多少客户。它可能会让人们轻松下载你的所有记录

  • ..以及为什么增量 ID/路由可能不好的另一个例子:

每个帖子都带有一个数字 ID,该 ID 从最近发布的帖子的 ID 开始递增

max*_*max 5

Rails 实际上并不关心您为模型使用的主要标识符。

当我们创建用户时,他们的 id 将为 1、2、3、4 等,他们的“show”路由将为 /show/:id

不正确。路线将是/users/?(:id). 运行rails routes | grep users查看生成的路由。

您的路由实际上不仅会匹配整数,还会匹配除指定段的有限子集(特别是).之外的任何字符。/:id

因此,它将与 users#show 操作匹配以下内容:

GET /users/1
GET /users/gabba-gabba-hey
GET /users/gabba%20gabba%20hey
Run Code Online (Sandbox Code Playgroud)

但不是:

GET /users/1/2
GET /users/gabba/gabba
GET /users/gabba/gabba/hey
Run Code Online (Sandbox Code Playgroud)

默认情况下,自动递增整数列用作 Rails 中的主键,因为它们简单、简短并且在 99% 的情况下都能完成工作。通常,如果您切换到 UUID,原因是您的操作规模需要多个数据库,并且按顺序生成 id 并不能解决问题。将标识符切换为随机生成的东西会使猜测变得更加困难,但仍然不能替代实际授权对资源的访问,因为它们仍然可能会泄漏到日志、电子邮件等中。

我可以想出一种手动执行此操作的方法,方法是在注册时添加一个附加列,其中包含随机 12 位整数,同时还要检查随机生成的整数是否尚不存在。但我想知道有没有更聪明的方法?

是的。不要重新发明轮子。

Ruby 已经有一个内置的SecureRandom#uuid方法,可以根据 RFC 4122生成UUID :

class User < ApplicationRecord
  def generate_uuid
    loop do
      self.uuid = SecureRandom.uuid
      break unless User.exists?(uuid: self.uuid)
    end
  end
end
Run Code Online (Sandbox Code Playgroud)

由于这里发生冲突的风险极低,因此该循环可能不会运行多次,并且它只是EXIST在(希望)索引的主键上运行查询 - 因此成本相对较低。

通过不仅使用整数,还使用字母,您可以生成更短的标识符,同时减少冲突的可能性。

如果您使用的数据库内置了 UUID 支持(例如 Postgres),那么这是一个更好的选择,因为这项工作实际上最好在数据库级别解决,因为它可以避免应用程序膨胀并减少开销。