为什么PG :: UniqueViolation:错误:重复键值违反了唯一约束?

时间:2017-11-30 15:58:00

标签: ruby-on-rails ruby postgresql

我有一个模型Post,每次创建帖子时,我都希望同时创建一个Moderation的新实例。

所以在post.rb中我使用了回调after_save :create_moderation 然后写一个私有方法:

 ...
 include Reportable
 after_save :create_moderation

 private
 def create_moderation
    self.create_moderation!(blog: Blog.first)
 end

但是当创建提案时,我收到此错误:

  
    

PG :: UniqueViolation:错误:重复键值违反了唯一约束" moderations_reportable" DETAIL:Key(reportable_type,reportable_id)=(Post,25)已经存在。 :INSERT INTO"审核" (" blog_id"," reportable_type"," reportable_id"," created_at"," updated_at"," blog_type")价值($ 1,$ 2,$ 3,$ 4,$ 5,$ 6)返回" id"

  

在reportable.rb中我有:

  has_one :moderation, as: :reportable, foreign_key: "reportable_id", foreign_type: "reportable_type", class_name: "Moderation"

然后很少有其他可报告对象的方法。

请注意,当我在控制台中运行create方法时,这个问题不会发生。

修改

  create_table "moderations", id: :serial, force: :cascade do |t|
    t.string "reportable_type", null: false
    t.string "reportable_id", null: false
    t.integer "blog_id", null: false
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
    t.string "blog_type", null: false
    t.string "upstream_moderation", default: "unmoderate"
    t.index ["blog_id", "blog_type"], name: "moderations_blog"
    t.index ["reportable_type", "reportable_id"], name: "moderations_reportable", unique: true
  end



create_table "posts", id: :serial, force: :cascade do |t|
    t.text "title", null: false
    t.text "body", null: false
    t.integer "feature_id", null: false
    t.integer "author_id"
    t.integer "scope_id"
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
    t.integer "post_votes_count", default: 0, null: false
    t.index ["body"], name: "post_body_search"
    t.index ["created_at"], name: "index_posts_on_created_at"
    t.index ["author_id"], name: "index_posts_on_author_id"
    t.index ["feature_id"], name: "index_posts_on_feature_id"
    t.index ["proposal_votes_count"], name: "index_posts_on_post_votes_count"
    t.index ["title"], name: "post_title_search"
  end

4 个答案:

答案 0 :(得分:18)

要解决此问题,我们必须告诉ActiveRecord查看表的序列:

ActiveRecord::Base.connection.reset_pk_sequence!('table_name')

现在ActiveRecord应该具有正确的序列值,并且应该能够正确分配新的id。

解决错误

  

PG :: UniqueViolation:错误:重复键值违反了唯一约束" moderations_reportable" DETAIL:Key(reportable_type,reportable_id)=(Post,25)已经存在。 :INSERT INTO"审核" (" blog_id"," reportable_type"," reportable_id"," created_at"," updated_at"," blog_type")价值($ 1,$ 2,$ 3,$ 4,$ 5,$ 6)返回" id"

由于'审核错误发生在'表

rails控制台修复

运行以下命令
ActiveRecord::Base.connection.reset_pk_sequence!('moderations')

谢谢

答案 1 :(得分:4)

看起来您已为数据库添加了唯一索引:

t.index ["reportable_type", "reportable_id"], name: "moderations_reportable", unique: true

使用唯一索引,您只能拥有一条具有相同reportable_typereportable_id的记录。您可能正在尝试为已经审核的报告创建审核。

答案 2 :(得分:4)

修复所有数据库的pkey序列:

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

答案 3 :(得分:1)

仅适用于在运行测试时看到此内容的人


一个可能的原因是,您有一些创建新数据记录的迁移,并且您最近运行了以下其中一项。

rake db:migrate RAILS_ENV=test

rake db:migrate:reset RAILS_ENV=test

解决方案

您需要清理/清除您的测试数据库。运行这个

rake db:reset RAILS_ENV=test

这将从 schema.rb 清除并生成架构。