web-dev-qa-db-fra.com

Rails identifiant d'attribution automatique qui existe déjà

Je crée un nouvel album comme ça:

truck = Truck.create(:name=>name, :user_id=>2)

Ma base de données compte actuellement plusieurs milliers d'entités pour les camions, mais j'ai attribué des identifiants à plusieurs d'entre eux, de manière à laisser certains identifiants disponibles. Donc, ce qui se passe est Rails crée un élément avec id = 150 et cela fonctionne très bien. Mais ensuite, il essaie de créer un élément et de lui attribuer id = 151, mais cet id peut déjà exister, donc je ' m voyant cette erreur:

ActiveRecord::RecordNotUnique (PG::Error: ERROR: duplicate key value violates unique constraint "companies_pkey" DETAIL: Key (id)=(151) already exists.

Et la prochaine fois que j'exécuterai l'action, il attribuera simplement l'ID 152, qui fonctionnera bien si cette valeur n'est pas déjà prise. Comment puis-je obtenir Rails pour vérifier si un ID existe déjà avant de l'attribuer?

Merci!

MODIFIER

L'ID de camion est ce qui est dupliqué. L'utilisateur existe déjà et est une constante dans ce cas. Il s'agit en fait d'un problème hérité auquel je dois faire face. Une option consiste à recréer la table à let Rails attribue automatiquement chaque identifiant cette fois-ci. Je commence à penser que cela peut être le meilleur choix car j'en ai quelques autres problèmes, mais la migration pour ce faire serait très compliquée car Truck est une clé étrangère dans de nombreuses autres tables. Existerait-il un moyen simple d'avoir Rails créer une nouvelle table avec les mêmes données déjà stocké sous Truck, avec des ID attribués automatiquement et maintenant toutes les relations existantes?

89
D-Nice

Rails utilise probablement la séquence PostgreSQL intégrée. L'idée d'une séquence est qu'elle n'est utilisée qu'une seule fois.

La solution la plus simple consiste à définir la séquence de votre colonne company.id sur la valeur la plus élevée du tableau avec une requête comme celle-ci:

SELECT setval('company_id_seq', (SELECT max(id) FROM company));

Je devine le nom de votre séquence "company_id_seq", le nom de la table "company" et le nom de la colonne "id" ... veuillez les remplacer par les bons. Vous pouvez obtenir le nom de la séquence avec SELECT pg_get_serial_sequence('tablename', 'columname'); ou regarder la définition de la table avec \d tablename.

Une autre solution consiste à remplacer la méthode save () dans votre classe d'entreprise pour définir manuellement l'ID d'entreprise pour les nouvelles lignes avant l'enregistrement.

86

J'ai fait cela qui a résolu le problème pour moi.

ActiveRecord::Base.connection.tables.each do |t|
  ActiveRecord::Base.connection.reset_pk_sequence!(t)
end

J'ai trouvé la reset_pk_sequence! à partir de ce fil. http://www.Ruby-forum.com/topic/64428

199
Apie

Basé sur @Apie réponse .

Vous pouvez créer une tâche et l'exécuter lorsque vous en avez besoin avec:

rake database:correction_seq_id

Vous créez des tâches comme celle-ci:

Rails g task database correction_seq_id

Et dans le fichier généré (lib/tasks/database.rake) mettre:

namespace :database do
    desc "Correction of sequences id"
    task correction_seq_id: :environment do
        ActiveRecord::Base.connection.tables.each do |t|
            ActiveRecord::Base.connection.reset_pk_sequence!(t)
        end
    end
end
25
inye

Cela me semble être un problème de base de données et non un problème Rails. Est-il possible que votre base de données ait une graine d'identité incorrecte dans votre colonne id? Pour tester, essayez de faire quelques insertions directement dans votre base de données et voyez si le même comportement existe.

4
mynameiscoffey

J'ai résolu ce problème en suivant la commande.

Exécutez ceci dans votre console Rails

ActiveRecord::Base.connection.reset_pk_sequence!('table_name')
0
Jigar Bhatt