这与 Rails 的关系不大,因为数据库的约定是使用自动递增主键。
对于新表,为防止 rails 使用此约定,您需要告诉它不要自动创建 id 列,而是自己创建。
# example of creating a users table
create_table :users, id: false do |t|
t.integer :id
# other column definitions
end
add_index :users, [:id], unique: true, name: 'index_id_on_users'
然后在您的模型中,您需要在创建记录之前明确设置。
class User < ActiveRecord::Base
before_create :set_id
def set_id
loop do
self.id = rand(1<<32)
break unless User.exists?(self.id)
end
end
end
循环只是确保你得到一个唯一的键,否则数据库约束会引发错误。仍然存在竞争条件,但如果您担心冲突而不是使用 UUID 或 SHA 之类的东西。
至于非整数键的问题,我自己从来没有遇到过任何问题,并且使用了 UUID 和 SHA 键,以及使用不是 id 列的主键,这只需要更多的配置。
对于您当前的模型,您必须从所有 id 中删除自动增量,否则我很确定数据库会忽略您告诉它的任何内容。这显然可以通过简单地在 id 上发出列更改迁移来完成。
change_column :users, :id, :integer
这里需要注意的是,您的 db/schema.rb 不会反映更改,使 db:schema:load 无法生成正确的数据库,尽管我可以说我从来没有使用过 rake 任务来加载数据库。只需使用 db:migrate 就可以了。
和往常一样,请确保在运行这样的命令之前备份您的数据库。我刚刚在我的开发环境中的 sqlite3 上运行它,它似乎工作正常。
更新 #1
如果您只关心 URL,则另一种方法是使用 slug 而不是 ID。有一些 gem 可以通过一些配置和一些新列来处理这个问题。基本上这个想法是有一个列用作 url 参数。因此,当您使用 URL 助手而不是输出 /resources/1 时,它将输出 /resources/some-url-friendly-slug。这可以是像 UUID 或 SHA 这样神秘的东西,也可以是对 SEO 友好的东西。这取决于模型中是否有可以击打的东西。例如,如果它是 product_path 并且产品有标题,那么 slug 可能是产品标题的 url 友好版本,非常适合 SEO。