如何避免 rails 'show' 路由中的序号整数路由(增量 ID)?

How to avoid ordinal, integer routes (incremental ids) in rails 'show' routes?

最简单的 MRE 是 rails g scaffold users

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

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

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

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

备注

each post carried a numerical ID that was incremented from the ID of the most recently published one

你可以使用UUID,它会给你随机的安全令牌,没有人能轻易理解用户的系列。

迁移如下所示

create_table :users, id: :uuid do |t|
      t.string   :name
      t.string   :phone
      ....
      t.timestamps
    end

希望对你有所帮助。

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

As we create users, their id will be 1, 2, 3, 4 etc, and their 'show' route will be /show/:id

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

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

因此会将以下内容匹配到用户#show 操作:

GET /users/1
GET /users/gabba-gabba-hey
GET /users/gabba%20gabba%20hey

但不是:

GET /users/1/2
GET /users/gabba/gabba
GET /users/gabba/gabba/hey

Auto-incrementing 整数列默认用作 Rails 中的主键,因为它们简单、简短并且在 99% 的时间内都可以完成工作。通常,如果您切换到 UUID,原因是您正在以需要多个数据库的规模进行操作,并且按顺序生成 ID 不会削减它。将标识符切换为随机生成的东西会使它变得更加难以猜测,但仍然不能替代实际授权访问资源,因为它们仍然可以泄露到日志、电子邮件等中。

I can think of a way to do it manually, by adding an additional column on sign up with a random 12 digit integer but also checking that the randomly generated integer doesn't already exist. But I wonder is there a smarter way?

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

Ruby 已经有内置 SecureRandom#uuid method which generates UUIDs according to RFC 4122:

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

由于此处发生冲突的风险极低,因此此循环可能 运行 不会超过一次,并且它只是 运行 在(希望)索引的 EXIST 上查询主键——所以成本比较低。

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

如果您使用的是像 Postgres 这样内置 UUID 支持的数据库,这是一个更好的选择,因为这是真正最好在数据库级别解决的工作,因为它避免了应用程序膨胀并减少了开销。