Rails自动分配已存在的id

D-N*_*ice 89 postgresql ruby-on-rails ruby-on-rails-3

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

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,如果尚未获取该值,则可以正常工作.如何在分配ID之前检查ID是否已存在?

谢谢!

编辑

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

Api*_*pie 199

我这样做了解决了我的问题.

ActiveRecord::Base.connection.tables.each do |t|
  ActiveRecord::Base.connection.reset_pk_sequence!(t)
end
Run Code Online (Sandbox Code Playgroud)

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

  • 或单线程等效(用于rails控制台复制/粘贴目的):`ActiveRecord :: Base.connection.tables.each {| t | ActiveRecord :: Base.connection.reset_pk_sequence!(t)}` (61认同)
  • 谢谢,最好的解决方案.数据库传输后我遇到了同样的问题. (4认同)
  • 应该接受答案!!一个人 (4认同)

Don*_*oma 86

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

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

SELECT setval('company_id_seq', (SELECT max(id) FROM company));
Run Code Online (Sandbox Code Playgroud)

我猜你的序列名称为"company_id_seq",表名为"company",列名为"id"......请用正确的名称替换它们.您可以使用SELECT pg_get_serial_sequence('tablename', 'columname');或获取表定义来获取序列名称\d tablename.

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

  • @Websitescenes,如果在PostgreSQL中有一个SERIAL列(一个串行列,其中默认值是序列中的下一个值),则在该列中使用硬值填充该表,该序列将不会自动更新.示例:`create table t(id serial not null primary key); 插入t值(1); 插入t值(默认值); 错误:重复键值违反唯一约束"t_pkey"DETAIL:键(id)=(1)已存在. (2认同)

iny*_*nye 25

基于@Apie 回答.

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

rake database:correction_seq_id
Run Code Online (Sandbox Code Playgroud)

你创建这样的任务:

rails g task database correction_seq_id
Run Code Online (Sandbox Code Playgroud)

并在文件generate(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
Run Code Online (Sandbox Code Playgroud)


Jig*_*att 6

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

在 Rails 控制台中运行它

ActiveRecord::Base.connection.reset_pk_sequence!('table_name')
Run Code Online (Sandbox Code Playgroud)