【问题标题】:why PG::UniqueViolation: ERROR: duplicate key value violates unique constraint?为什么 PG::UniqueViolation: ERROR: 重复键值违反唯一约束?
【发布时间】:2018-05-14 14:57:01
【问题描述】:

我有一个模型 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”详细信息:键(reportable_type,reportable_id)=(Post,25)已经存在。 :插入“审核”(“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

【问题讨论】:

  • 请也向您展示迁移,因为这是数据库错误而不是 ORM 错误
  • @engineersmnky 我编辑了我的帖子
  • 而这个t.index ["reportable_type", "reportable_id"], name: "moderations_reportable", unique: true 没有泄露出去?
  • 抱歉复制粘贴错误
  • 没有错误,该行仍然是数据库键约束的一部分。我认为您想将挂钩更改为after_create 而不是after_save,因为save 也会在update 上被调用

标签: ruby-on-rails ruby postgresql


【解决方案1】:

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


一个可能的原因是,您进行了一些创建新数据记录的迁移,并且您最近运行了以下操作之一。

rake db:migrate RAILS_ENV=test

rake db:migrate:reset RAILS_ENV=test

解决方案

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

rake db:reset RAILS_ENV=test

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

【讨论】:

    【解决方案2】:

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

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

    【讨论】:

      【解决方案3】:

      要解决这个问题,我们必须告诉 ActiveRecord 查看表格的顺序:

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

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

      解决错误

      PG::UniqueViolation:错误:重复的键值违反了唯一约束“moderations_reportable”详细信息:键(reportable_type,reportable_id)=(Post,25)已经存在。 :插入“审核”(“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')
      

      谢谢

      【讨论】:

      • 你是冠军我的朋友。这是永久解决方案吗?你认为这个问题会再次出现吗?
      • 是的,但是如果你再弄乱了,你需要重新设置序列。
      • 你是对的,你有什么自动解决方案吗?
      • 这为我保存了一些完全无关的东西。太棒了。
      【解决方案4】:

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

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

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-02-11
        • 2015-03-24
        • 1970-01-01
        • 2022-01-13
        • 2020-03-27
        • 2013-06-23
        相关资源
        最近更新 更多