2009-01-13 9 views
16

J'ai une petite base de données et j'ai ajouté des entrées via une page Rails. J'ai "détruit" l'une des entrées et maintenant ma séquence d'identifiants est sautée par un. Par exemple, j'ai maintenant 42 puis 44, au lieu de l'évidence: 42, 43, 44.Modification des ID de base de données à partir de la console Rails?

Je me demandais s'il y avait un moyen d'éditer le numéro d'identification d'un nouvel objet à travers la console. J'ai essayé:

record.id = 43 
record.save 

et

record = record.new 
record.attributes = { :id => 43 } 

, mais les deux ne fonctionnent pas. Je suis à peu près certain qu'il doit y avoir une méthode console pour cela, mais je n'arrive pas à trouver beaucoup de détails sur Google et j'ai probablement mal lu l'API Rails ... Aurais-je besoin de le faire via SQL direct dans sqlite ?

Merci

Répondre

4

Est-ce que je dois peut-être de le faire par SQL directe sqlite?

Oui.

Le but d'ActiveRecord est de faire abstraction des fonctions de base de données et de retourner simplement des collections de données. Vous ne devriez pas vous inquiéter de l'ID d'un enregistrement, c'est quelque chose de spécifique à la base de données. Du haut de ma tête, je ne vois aucune raison de référencer l'identifiant du modèle.

Si votre application dépend d'un numéro séquentiel, vous devez ajouter un autre champ au modèle qui l'a. Par exemple, si j'ai un magasin avec des produits (un modèle de produit) et que je donne le numéro d'identification que la base de données fournit à d'autres fournisseurs. Deux semaines plus tard, mon patron me demande d'avoir un ID unique mais similaire pour deux variantes de produits: "45a" et "45b". Des noisettes. Le champ ID ne doit être utilisé que pour la base de données et ActiveRecord, pas vous ou vos utilisateurs, pour identifier l'enregistrement.

Il y a une petite chance que soit peut être une méthode obscure qui force l'ID si la DB le permet, mais elle est obscure pour une raison. N'essayez pas de le trouver :)

Tout cela étant dit, tapez ruby script/dbconsole pour remonter rapidement l'interface sqlite sans avoir à taper votre mot de passe.

Aussi, si vous supprimez la base de données sqlite qui va réinitialiser le compteur et commencer à 0. Avec une grande puissance vient une grande responsabilité.

EDIT

Si je me souviens bien Dave Thomas a écrit à ce sujet quelque part. Peut-être here?

+1

C'était un commentaire vraiment sarcastique et inutile. Ne vaut pas la peine de signaler, mais mérite d'être révisé. – ivanreese

23

En fait, vous pouvez définir l'ID manuellement pour les nouveaux objets:

record = Record.new 
record.id = 1234 
record.save 

Cependant, ce que vous essayez de faire est de mettre à jour l'identifiant d'un objet existant.Lorsque vous définissez record.id = 43 puis appelez save ce qui se passe est que ActiveRecord va essayer de générer des requêtes SQL comme ceci:

update records set id = 43 where id = 43

Notez que l'identifiant qu'il cherche à mettre à jour est le même que celui que vous essayez pour changer. C'est pourquoi ça ne marche pas.

Alors oui, vous devrez utiliser SQL pour changer cela. Que ce soit une bonne idée ou non est un autre problème, mais il faut parfois le faire.

+0

Le premier code a fonctionné pour moi. Merci! –

+1

Grande solution, je voudrais pouvoir doubler le vote pour l'obtenir au sommet. J'aime les solutions qui expliquent le problème. Et j'ai trouvé l'utilité de cela pour implémenter des «enums» normalisés. Par exemple, un utilisateur peut avoir de nombreux rôles, mais ces rôles vont être cohérents à travers les déploiements, donc je les ajoute avec une tâche rake. Le codage en dur de leurs identifiants garantit qu'ils sont identiques sur ma boîte locale et sur le serveur. Nitpicky, et peut-être jamais nécessaire, mais ça me rend un peu moins nerveux :) –

39

La meilleure façon de le faire est d'exécuter directement le SQL et de résoudre ce problème temporel dans la séquence.

Essayez d'accéder à la console (script Ruby/console) et tapez:

>> sql = "update records set id=43 where id=44" 
>> ActiveRecord::Base.connection.execute(sql) 

Où 44 est l'identifiant de l'objet nouvellement créé, et 43 est celui que vous manque dans votre table

Bonne chance !

+0

Ca a marché pour moi. Merci! –

+1

Je suis d'accord que changer un ID est une mauvaise idée, mais quand vous avez besoin de restaurer des données, oh, disons, une base de données de production lorsque vous avez «perdu» certains enregistrements? C'est parfait. –

+2

aussi bien si vous avez deux systèmes qui doivent se synchroniser .. – baash05

Questions connexes