2016-04-06 3 views
0

Ich benutze postgresql und Schienen 4.2 für meine Anwendungsentwicklung. HierRails Transaktion Rollback führt zu diskontinuierlichen ID

ist die Frage:

Wenn ein Benutzermodell erstellt wird, muß ich zwei andere Modelle mit Benutzermodell zugeordnet auf mittlerweile erstellt werden: Profilmodell und user_behavior Modell. Im Falle der Konsistenz von Datensätzen zu halten, wird Transaktion wie folgt verwendet:

begin 
    @new_user = User.new 
    @new_user.transaction do 
    @new_user.update_attributes!(users_params) 
    @new_user.profile = Profile.create!(profiles_params) 
    @new_user.user_behavior = UserBehavior.create! 
    end 
rescue ActiveRecord::RecordInvalid => exception 
    render_response_msg(4003, { message: exception.message }) 
rescue ArgumentError => exception 
    render_response_msg(4003, { message: "invalid parameters" }) 
end 
@new_user 

Beide Benutzermodell und Profilmodell hat einige Validierungen

Problem 1. Ich verwende eine Instanzvariable @new_user zu bringe den neu erstellten Benutzerdatensatz aus dem Transaktionsbereich heraus, ich bin nicht sicher, ob dies eine generische Methode ist, um dies zu tun, irgendwelche anderen Ideen?

Problem 2. wenn der Benutzer params ist gut, übergibt es und erstellt einen Benutzerdatensatz, dann Profilparameter ist nicht gültig, macht die gesamte Transaktion Rollback. Dann fand ich die ID (Basic Auto Increment ID des Modells in Schienen) des Benutzermodells ist diskontinuierlich. Wenn es beispielsweise aufgrund von Profilparametern zweimal fehlschlägt, erstellt die Erfolgs-Transaktion ein Modell mit der ID = 3. Wie kann ich das beheben?

+0

Warum sind Lücken in 'ID'-Werten ein Problem? Sie werden einzigartig sein, das ist alles, was wirklich garantiert ist. –

Antwort

0

[Bearbeiten Sie die Antwort auf das Problem 1, weil die lokale Variable nicht möglich ist, nicht zurückgeführt werden kann, wie ich in meinem Kommentar darauf hingewiesen hatte, vermisste ich, dass in meinem ursprünglichen Beitrag]

Als Antwort auf das Problem 1: Ich denke, die Beschreibung in diesem Artikel http://api.rubyonrails.org/classes/ActiveRecord/Transactions/ClassMethods.html wäre hilfreich. Folglich würde ich etwas tun, wie folgt:

User.transaction do 
    new_user = User.new(user_params) 
    new_user.profile = Profile.create!(profile_params) 
    new_user.behavior = UserBehavior.create! 
    new_user.save! 
end 

Als Reaktion auf Problem 2: als mu is too short wies darauf hin, es sollte keine Rolle spielen, aber postgresql verwendet für jede Tabelle in der Datenbank eine Sequenztabelle allgemein genannt [YOUR_TABLE_NAME]_id_seq müssen Sie Ändern Sie den Wert der last_value-Spalte in dieser Tabelle, um die ID-Sequenz anzupassen, aber ein Fehler würde definitiv eine Menge Probleme hinsichtlich der Beibehaltung der Eindeutigkeit verursachen, und ich würde sicherlich davon abraten, damit herumzuspielen.

+0

Hinweis Ich muss einen neu erstellten Benutzerdatensatz in dieser Methode zurückgeben, wenn ** new_user ** als lokale Variable verwendet wird, kann ich die Entität nicht aus dem Transaktionsbereich abrufen. – user6164268

+0

Oh ja! Es tut mir so leid, dass ich das absolut vermisst habe. Ich werde meine Antwort bearbeiten –

+0

Auch ich denke, dass Sie erreichen können, was Sie ohne eine Instanzvariable versuchen, wenn Sie Ihre Variable als 'new_user' vor der Transaktion initialisieren, sollte es noch innerhalb der 'begin'-Block zugänglich sein. Sie können 'return new_user' direkt vor' rescue ActiveRecord :: RecordInvalid => exception 'hinzufügen und wenn Sie nicht zu diesem Zeitpunkt zurückkehren wollen und new_user außerhalb des 'begin'-Blocks zugänglich machen wollen, initialisieren Sie' new_user' vor dem 'begin 'Block beginnt. –