5

The article_id is in the Pictures table, as it has to be, because each article can have many pictures.

so the Picture table would look like this:

id        article_id         picture

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

etc

I know the difference between destroy_all (which instantiates an object on the dependent table and calls its destroy method and it is a slow process) and delete_all which simply wipes out records without caring about associations.

But I have to use destroy_all because THERE ARE associated dependent records:

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

SCHEMA

 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

So, both commands, Article.delete_all and Article.destroy_all

bring a similar complaint

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

UPDATE

I have tried adding the on delete cascade FK in the migration files, to no avail:

I first removed the FK as I had to add the qualifier: on_delete: :cascade

class RemoveFkFromPictures < ActiveRecord::Migration
  def change

    remove_foreign_key :pictures, column: :article_id
  end
end

I created another migration file to add the FK

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

  end
end

and the schema looks like:

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

so, you would think that it is ok now. Well, it is not:

  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
user229044
  • 232,980
  • 40
  • 330
  • 338
Arminius
  • 606
  • 1
  • 6
  • 19
  • Those ** are not in your model are they, you are just using them to highlight. You can create a fk that cascade deletes in rails. All depends on if you want rails to delete it or the database. – Doon Mar 05 '16 at 21:30
  • http://stackoverflow.com/questions/29544693/cant-delete-object-due-to-foreign-key-constraint/29544875#29544875 – Doon Mar 05 '16 at 21:31
  • You need to write the migration code yourself. The generator won't do it for you. – Doon Mar 06 '16 at 15:39
  • Use remove_foreign_key and then add_foreign_key in te migration to change it. Also you can use execute to run your own SQL there – Doon Mar 06 '16 at 16:53
  • It is confirmed. That has not solved the issue. I reset the whole db, remove the migration files. removed the foreign key, checked with the schema file that the foreign key was first present (without the on delete cascade) and then created another migration adding the on_delete cascade like this: add_foreign_key :pictures, :articles, on_delete: :cascade the schema file clearly showed the change and displayed this info: add_foreign_key "articles", "users" add_foreign_key "pictures", "articles", on_delete: :cascade end Then I tried to delete and I got the error: failed to destroy record. – Arminius Mar 07 '16 at 23:17

1 Answers1

4

first I want to thank you for your insight and good will to help.

Taking it from where you left it off, I tell you how I solved this, which had me 2 days, until today when waking up, I thought I could try it.

1) Indeed, writing just dependent: :destroy at the Parent model will not suffice. It seems that Ruby is not actually doing the job of "leaving no orphans" when you actually meant "on delete, cascade", thought to be represented by that, "destroy".

2) When you generate a Model creating the Fk, say user: references, it does create a FK which you can see in the schema.rb file, but, as you pointed out, by default is "restrict", that is, do nothing to children.

3) Then we are screwed. Because neither will destroy do the Herodes thing, nor will the FK.

4) You need to remove the FK from the migration file, replace it by an FK with a "on delete cascade"

AND

5) You need to remove the dependent: : destroy which still sit in the Model.

6) This way, the low level database command will take over and the deletion proceeds clean and quick.

Arminius
  • 606
  • 1
  • 6
  • 19