web-dev-qa-db-fra.com

ERREUR: la suppression sur la table viole la contrainte de clé étrangère. L'identifiant de la clé est toujours référencé à partir de la table (plusieurs)

Je travaille avec Rails et PostgreSQL et j'ai une relation de base un-à-plusieurs en cours, un Auction a plusieurs Bids. Cependant, quand j'essaie et supprimer une enchère (avec des offres présentes), j'obtiens l'erreur suivante:

ERREUR: la mise à jour ou la suppression sur la table "enchères" viole la contrainte de clé étrangère "fk_Rails_43e9021cbf" sur la table "enchères". DÉTAIL: La clé (id) = (1) est toujours référencée dans le tableau "enchères".

La suppression d'enchères sans enchères ne donne aucune erreur.

La partie qui m'embrouille est qu'à l'intérieur de mon modèle Auction, j'ai:

has_many :bids, dependent: :destroy

Error Screen Shot (better_error gem)

Étant donné que j'ai une clause de destruction dépendante, pourquoi ai-je toujours cette erreur?

EDIT: J'ai essayé de supprimer toute la base de données, puis de tout recréer/re-migrer - toujours la même erreur.

40
SUPER USER

Mon problème était que j'utilise @auction.delete (visible dans la capture d'écran que j'ai publiée) lorsque vous essayez de supprimer un enregistrement.

Supprimer ignorera tous les rappels que j'ai en place. Donc, même si j'ai une clause destroy dépendante, elle n'est pas appelée - d'où Rails génère une erreur. Si/quand j'ai changé le code pour lire @auction.destroy, le rappel a été invoqué et a résolu le problème.

Référence: différence entre détruire et supprimer

13
SUPER USER

Depuis Rails v4.2 vous pouvez le faire:

Créez une migration pour mettre à jour les clés étrangères

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
34
Mohamed Ziata

Utilisez-vous delete ou destroy pour supprimer les objets? Je pense que vous utilisez delete et que vous souhaitez utiliser destroy

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

17
John Naegle

Utilisez-vous par hasard la gemme paranoïa ou quelque chose du genre?

Si vous êtes bids sont paranoid et auctions ne le sont pas, vous pouvez rencontrer cette erreur.

Cela se produirait car lorsque Rails exécute le dependent: destroy, il supprime les offres en douceur, mais elles existent toujours dans la base de données (elles ont juste le deleted_at jeu de colonnes). Par conséquent, la contrainte de clé étrangère échouerait.

8
steveklbnf

Votre erreur provient de la base de données et non de Rails. Vous devez d'abord supprimer les enchères dans votre application ou modifier la contrainte de clé étrangère dans la base de données pour mettre en cascade la suppression.

4
Tony Hopkinson

Marc Busqué a n très bon article à propos de ce problème qui pourrait aider.

"Lorsqu'ActiveRecord rencontre une violation de clé étrangère, il déclenche une exception ActiveRecord :: InvalidForeignKey. Même si dans sa documentation, il indique simplement qu'il est déclenché lorsqu'un enregistrement ne peut pas être inséré ou mis à jour car il fait référence à un enregistrement inexistant, le fait est qu'il est également utilisé dans le cas qui nous intéresse. "

Avec cela et un rescue_from, nous pouvons simplement ajouter à ApplicationController ou à une préoccupation de contrôleur:

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