错误:表上的删除违反了外键约束。密钥id仍然从表中引用(很多)

时间:2015-03-11 20:33:03

标签: ruby-on-rails postgresql sublimetext2 better-errors-gem

我正在使用Rails和PostgreSQL并且正在进行基本的一对多关系,一个Auction有很多Bid个。但是,当我尝试删除拍卖(有出价)时,我收到以下错误:

  

错误:表格上的更新或删除“拍卖”违反了外键   表“出价”上的约束“fk_rails_43e9021cbf”。细节:钥匙(id)=(1)   仍然从表格“出价”中引用。

删除没有出价的拍卖会没有错误。

困扰我的部分是我的Auction模型中,我有:

has_many :bids, dependent: :destroy

Error Screen Shot (better_error gem)

由于我有一个依赖的destroy子句,为什么我仍然会收到此错误?

编辑:我尝试删除整个数据库,然后重新创建/重新迁移所有内容 - 仍然会遇到相同的错误。

8 个答案:

答案 0 :(得分:34)

Rails v4.2 ,你可以这样做:

创建迁移以更新外键

<强> 20160321165946_update_foreign_key.rb

class UpdateForeignKey < ActiveRecord::Migration
  def change
    # remove the old foreign_key
    remove_foreign_key :posts, :users

    # add the new foreign_key
    add_foreign_key :posts, :users, on_delete: :cascade
  end
end

答案 1 :(得分:16)

您使用deletedestroy删除对象吗?我认为您使用的是delete,并且您想使用destroy

请参阅http://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html#module-ActiveRecord::Associations::ClassMethods-label-Delete+or+destroy-3F

答案 2 :(得分:12)

我的问题是我在尝试删除记录时使用@ auction.delete(在我发布的屏幕截图中可见)。

删除将忽略我所拥有的任何回调。所以即使我有一个依赖的destroy子句,它也没有被调用 - 因此Rails会抛出一个错误。如果/当我将代码更改为@ auction.destroy时,调用了回调并解决了问题。

参考: Difference between Destroy and Delete

答案 3 :(得分:8)

您是否偶然使用paranoia宝石或类似的东西?

如果您bids paranoidauctions不是dependent: destroy,则可能会遇到此错误。

这会发生,因为当rails执行deleted_at时,它会软删除出价,但它们实际上仍存在于数据库中(它们只设置了public static Result myprofile() { DynamicForm requestData = Form.form().bindFromRequest(); Integer id = Integer.parseInt(requestData.get("id")); try { JSONObject jo = null; Connection conn = DB.getConnection(); ResultSet rs; JSONArray ja = new JSONArray(); PreparedStatement ps = conn.prepareStatement("SELECT p.fullname as fullname, s.post as post,to_char(s.created_on, 'MON DD,YYYY') as created_on,s.last_reply as last_reply,s.id as id,s.comments as comments,s.state as state,s.city as city,s.id as id FROM profiles as p INNER JOIN streams as s ON (s.profile_id=p.id) WHERE s.profile_id=? order by created_on desc"); ps.setInt(1, id); rs = ps.executeQuery(); while (rs.next()) { jo = new JSONObject(); jo.put("fullname", rs.getString("fullname")); jo.put("post", rs.getString("post")); jo.put("city", rs.getString("city")); jo.put("state", rs.getString("state")); jo.put("comments", rs.getInt("comments")); jo.put("id", rs.getInt("id")); jo.put("last_reply", difference(rs.getInt("last_reply"), rs.getString("created_on"))); ja.put(jo); } JSONObject mainObj = new JSONObject(); mainObj.put("myprofile", ja); String total = mainObj.toString(); System.err.println(total); conn.close(); return ok(total); } catch (Exception e) { e.getMessage(); } return ok(); } 列)。因此,外键约束将失败。

答案 4 :(得分:4)

您的错误来自数据库而不是rails。您需要先在应用中删除出价,或更改数据库中的外键约束以级联删除

答案 5 :(得分:1)

MarcBusquéa very good article对此问题有所帮助。

“当ActiveRecord遇到外键违规时,它会引发一个ActiveRecord :: InvalidForeignKey异常。即使在其文档中它只是说当一条记录无法插入或更新时引发它,因为它引用了一条不存在的记录,事实是它也用于我们感兴趣的情况。“

有了这个和rescue_from,我们可以添加到ApplicationController或控制器关注:

rescue_from 'ActiveRecord::InvalidForeignKey' do
  # Flash and render, render API json error... whatever
end

答案 6 :(得分:0)

其他答案也不错,但是请不要提及有时您要保留从属记录,而使外键无效

class Post < ActiveRecord::Base
  has_many :comments, dependent: :nullify
end

请注意,这将需要确保数据库表中的外键列为空:true

我不是很肯定,但是您可能还需要在依赖模型中定义的归属关联中添加 可选:true

答案 7 :(得分:0)

一个非常简单的解释:关联的表至少包含1条记录,这些记录已连接到您要销毁的表中的记录。

要解决此问题,请添加dependent: :destroy(假设用户有has_many个帖子)

has_many :post, dependent: :destroy