98

我像这样创建一个新记录:

truck = Truck.create(:name=>name, :user_id=>2)

我的数据库目前有数千个卡车实体,但我将 id 分配给了其中几个实体,以某种方式留下了一些可用的 id。所以发生的事情是 rails 创建了 id = 150 的项目,它工作正常。但随后它尝试创建一个项目并将其分配 id = 151,但该 id 可能已经存在,所以我看到了这个错误:

ActiveRecord::RecordNotUnique (PG::Error: ERROR: duplicate key value violates unique constraint "companies_pkey" DETAIL: Key (id)=(151) already exists.

下次我运行该操作时,它会简单地分配 id 152,如果尚未采用该值,它将正常工作。如何让 rails 在分配 ID 之前检查它是否已经存在?

谢谢!

编辑

Truck id 是被复制的内容。用户已经存在并且在这种情况下是一个常量。这实际上是我必须处理的遗留问题。一种选择是,这次在 let rails auto assign each id 时重新创建表。我开始认为这可能是最好的选择,因为我还有其他一些问题,但是这样做的迁移会非常复杂,因为 Truck 是许多其他表中的外键。是否有一种简单的方法可以让 rails 创建一个新表,其中包含已存储在 Truck 下的相同数据、自动分配的 ID 并维护所有现有关系?

4

5 回答 5

210

我这样做为我解决了这个问题。

ActiveRecord::Base.connection.tables.each do |t|
  ActiveRecord::Base.connection.reset_pk_sequence!(t)
end

我找到了reset_pk_sequence!从这个线程。http://www.ruby-forum.com/topic/64428

于 2013-02-27T09:40:48.637 回答
89

Rails 可能正在使用内置的 PostgreSQL 序列。序列的想法是它只使用一次。

最简单的解决方案是使用如下查询将 company.id 列的序列设置为表中的最大值:

SELECT setval('company_id_seq', (SELECT max(id) FROM company));

我猜你的序列名“company_id_seq”、表名“company”和列名“id”……请用正确的替换它们。您可以使用 获取序列名称SELECT pg_get_serial_sequence('tablename', 'columname');或查看表定义\d tablename

另一种解决方案是覆盖公司类中的 save() 方法,以便在保存之前手动设置新行的公司 ID。

于 2012-06-17T04:43:40.890 回答
27

基于@Apie答案

您可以创建一个任务并在需要时运行:

rake database:correction_seq_id

你创建这样的任务:

rails g task database correction_seq_id

并在生成的文件中 ( lib/tasks/database.rake) 放入:

namespace :database do
    desc "Correction of sequences id"
    task correction_seq_id: :environment do
        ActiveRecord::Base.connection.tables.each do |t|
            ActiveRecord::Base.connection.reset_pk_sequence!(t)
        end
    end
end
于 2015-09-09T16:34:36.407 回答
6

我通过以下命令解决了这个问题。

在你的 Rails 控制台中运行它

ActiveRecord::Base.connection.reset_pk_sequence!('table_name')
于 2019-07-03T06:08:24.183 回答
4

对我来说听起来像是数据库问题而不是 Rails 问题。您的数据库是否可能在您的id列上有不正确的身份种子?要进行测试,请尝试直接在您的数据库中插入几次,看看是否存在相同的行为。

于 2012-06-17T04:12:35.787 回答