【问题标题】:Rails: why cannot delete dependent table if dependent: :destroy allowed?Rails:如果依赖::destroy 允许,为什么不能删除依赖表?
【发布时间】:2016-06-19 06:52:49
【问题描述】:

article_id 必须在图片表中,因为每篇文章可以有很多图片。

所以图片表看起来像这样:

id        article_id         picture

1           34              pinguin.jpg
2           56              koala.jpg
3           56              bear.jpg

我知道destroy_all(在依赖表上实例化一个对象并调用它的destroy方法,这是一个缓慢的过程)和delete_all之间的区别,它只是清除记录而不关心关联。

但我必须使用 destroy_all 因为有相关的依赖记录:

Article Model
    class Article < ActiveRecord::Base
      belongs_to :user
      has_many :pictures , **`dependent: :destroy`**
      accepts_nested_attributes_for :pictures

Picture Model
    class Picture < ActiveRecord::Base
      belongs_to :article
     mount_uploader :picture, PictureUploader

     def destroy
     end

架构

 create_table "articles", force: :cascade do |t|
    t.string   "country"
    t.string   "region"
    t.string   "town"
    t.string   "street"
    t.string   "company"
    t.string   "title"
    t.text     "content"
    t.integer  "user_id"
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
  end

  add_index "articles", ["user_id", "created_at"], name: "index_articles_on_user_id_and_created_at", using: :btree
  add_index "articles", ["user_id"], name: "index_articles_on_user_id", using: :btree

  create_table "pictures", force: :cascade do |t|
    t.integer  "article_id"
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
    t.string   "picture"
  end

所以,Article.delete_all 和 Article.destroy_all 这两个命令

提出类似的投诉

Article.destroy_all
  Article Load (0.9ms)  SELECT "articles".* FROM "articles"  ORDER BY "articles"."created_at" DESC
   (0.1ms)  BEGIN
  SQL (1.7ms)  DELETE FROM "articles" WHERE "articles"."id" = $1  [["id", 21]]
PG::ForeignKeyViolation: ERROR:  update or delete on table "articles" violates foreign key constraint "fk_rails_658164416e" on table "pictures"
DETAIL:  Key (id)=(21) is still referenced from table "pictures".
: DELETE FROM "articles" WHERE "articles"."id" = $1
   (0.2ms)  ROLLBACK


class CreatePictures < ActiveRecord::Migration
  def change
    create_table :pictures do |t|
      t.references :article, index: true, foreign_key: true

      t.timestamps null: false
    end
  end
end

更新

我已尝试在迁移文件中添加 on delete 级联 FK,但无济于事:

我首先删除了 FK,因为我必须添加限定符:on_delete: :cascade

class RemoveFkFromPictures < ActiveRecord::Migration
  def change

    remove_foreign_key :pictures, column: :article_id
  end
end

我创建了另一个迁移文件来添加 FK

class AddForeignKeyToPictures1 < ActiveRecord::Migration
  def change
    add_foreign_key :pictures, :articles, on_delete: :cascade , name: :deletingarticlescascadesonpictures

  end
end

架构看起来像:

add_index "users", ["email"], name: "index_users_on_email", unique: true, using: :btree

  add_foreign_key "articles", "users"
  add_foreign_key "pictures", "articles", name: "deletingarticlescascadesonpictures", on_delete: :cascade
end

所以,你会认为现在没问题。好吧,它不是:

  Article Load (1.3ms)  SELECT "articles".* FROM "articles"  ORDER BY "articles"."created_at" DESC
   (0.2ms)  BEGIN
  Picture Load (0.5ms)  SELECT "pictures".* FROM "pictures" WHERE "pictures"."article_id" = $1  [["article_id", 25]]
   (0.4ms)  ROLLBACK
ActiveRecord::RecordNotDestroyed: Failed to destroy the record

【问题讨论】:

  • 那些**不在你的模型中,你只是用它们来突出显示。您可以创建一个在 rails 中级联删除的 fk。一切都取决于您是否希望 rails 删除它或数据库。
  • 您需要自己编写迁移代码。生成器不会为您执行此操作。
  • 在迁移中使用 remove_foreign_key 然后 add_foreign_key 来改变它。您也可以使用 execute 在那里运行您自己的 SQL
  • 已确认。那还没有解决问题。我重置了整个数据库,删除了迁移文件。删除外键,检查外键首先存在的架构文件(没有 on delete 级联),然后创建另一个迁移添加 on_delete 级联,如下所示: add_foreign_key :pictures, :articles, on_delete: :cascade 架构文件清楚地显示了更改并显示了以下信息: add_foreign_key "articles", "users" add_foreign_key "pictures", "articles", on_delete: :cascade end 然后我尝试删除并得到错误:未能销毁记录。

标签: ruby-on-rails


【解决方案1】:

首先,我要感谢您的洞察力和热心帮助。

从你离开的地方开始,我告诉你我是如何解决这个问题的,我花了 2 天时间,直到今天醒来,我想我可以试试。

1) 实际上,仅在 Parent 模型中编写dependent: :destroy 是不够的。当您实际上的意思是“删除时,级联”时,Ruby 似乎并没有真正做“不留下孤儿”的工作,被认为是用“销毁”来表示。

2) 当您生成创建 Fk 的模型时,比如说 user: references,它确实会创建一个 FK,您可以在 schema.rb 文件中看到它,但是,正如您所指出的,默认情况下是“restrict”,即就是,不要对孩子做任何事。

3) 那我们就完蛋了。因为Herodes和FK都不会破坏。

4) 您需要从迁移文件中删除 FK,将其替换为带有“on delete cascade”的 FK

5) 你需要删除依赖的::destroy 仍然位于模型中。

6) 这样,低级数据库命令将接管,删除过程干净而快速。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-12-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-07-29
    • 2018-05-18
    • 2019-09-20
    相关资源
    最近更新 更多