Je travaille avec Rails et PostgreSQL et j'ai une relation de base un-à-plusieurs en cours, un Auction
a plusieurs Bid
s. 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
É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.
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
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
Utilisez-vous delete
ou destroy
pour supprimer les objets? Je pense que vous utilisez delete
et que vous souhaitez utiliser destroy
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.
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.
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