2012-11-09 9 views
9

Ich habe ein Modell, das eine Anzahl von has_many und has_many: durch Modellbeziehungen hat. Zum Beispiel in meiner Klasse User Ich habe:Erkennen von Änderungen in einem Schienen has_many: durch Beziehung

has_many: Sprachen, durch: profile_languages ​​

Was würde ich ist gerne in der Lage sein zu erkennen, wenn diese hinzugefügt oder entfernt werden mit der Funktion ‚User.changes‘ , die ein Array von Attributen zurückgibt, die beim Aufruf mit der Funktion User.language_ids = geändert wurden.

Hat jemand anderes versucht, dies zu tun, oder haben Sie Erfahrung damit?

Info auf der ActiveModel ändert Funktion: http://api.rubyonrails.org/classes/ActiveModel/Dirty.html

Edit: Wie gewünscht, hier ist das, was ich tue.

Nachdem die Attribute eines Benutzers zugewiesen und bevor es gespeichert wird, schaue ich alle von den .changes zurückgegebenen Werte an, um alle in einem externen Protokoll vorgenommenen Änderungen zu protokollieren.

Also, wenn ich rufe u.name = "neuen Namen"

dann u.changes kehrt {name: [ 'alte Name', 'new name']}

Allerdings, wenn ich ein Pass Benutzer eine Reihe von Sprach-IDs, wie

u.language_ids = [4,5]

Dann gibt es eine Reihe von ProfileLanguage Modelle erstellt und die u.changes Hash wird leer gelassen.

Ich versuche, einige Callbacks im ProfileLanguage-Modell zu erstellen, das manuell eine Art Hash erstellen würde, aber ich frage mich, ob dies tatsächlich die beste Lösung ist.

+0

Hallo Ron, kannst du bitte etwas genauer zu deiner Frage sein? Vielleicht zeigen Sie uns, was Sie bisher aufgebaut haben, damit wir etwas haben können. – Noz

+0

Haben Sie Rückrufe oder Beobachter untersucht? – Ari

+0

Eine Bearbeitung hinzugefügt. Hoffentlich kann es klären –

Antwort

10

Meine etwas schmutzige Lösung, die ich mit jetzt werde, ist Rückrufe auf die has_many Funktion hinzuzufügen:

has_many :languages, through: :profile_languages, 
     :after_add => :language_add, 
     :before_remove => :language_remove 

Und das Hinzufügen dieser Informationen zu einem benutzerdefinierten Hash, der auf das Speichern eines Profils überprüft werden, wenn ich bin Blick auf die .changes-Funktion.

+0

Das funktioniert nicht für mich. Es scheint, dass die Callbacks "after_add" und "before_remove" nicht ausgelöst werden, wenn Sie Massenzuweisungen ausführen (wie das mit den Sprach-IDs). Mache ich etwas falsch? – morgler

+0

Es funktioniert, diese Callbacks werden dann für jedes entfernende Objekt separat aufgerufen. –

0

Ich hatte das gleiche Problem, ich habe versucht zu überprüfen, ob eine neue Beziehung erstellt oder gelöscht wurde, wenn ein Modell aktualisiert wird.

Ich versuchte mit model.relationship.any? { |a| a.changed? }, aber dies erkennt nur Änderungen von bereits vorhandenen Objekten, so dass es nicht beim Erstellen und Löschen von Beziehungen gearbeitet hat.

Suche nach einer Lösung, fand ich diese sehr kurze Artikel, die unser Problem löst: link

Mit model.select { |a| a.new_record? || e.marked_for_destruction? }.any? Ich habe in der Lage, um alle Aufzeichnungen zu erhalten, die erzeugt oder zerstört werden.

Kombinieren Sie dies mit a.changed? Ich kann alle Änderungen in meiner Beziehung bekommen.

+0

Funktioniert mit 'accept_nested_attributes_for', aber nicht generell. – maxhs

0

Ich weiß, dass Sie suchen, um ein textbasiertes Protokoll der Änderungen zu implementieren, aber ich würde empfehlen, die vollständige Versionierung von Objekten durch die paper_trail Edelstein als eine Methode, um zu erreichen, was Sie wollen.Es bietet this functionality according to their README:

PaperTrail drei Arten von Verbänden wiederherstellen: Hat-One Has-Viele und hat-Many-Through. Um dies zu tun, müssen Sie eine Tabelle version_associations erstellen, entweder zur Installationszeit mit den Optionen rails generate paper_trail: install --with-associations oder manuell. PaperTrail speichert in dieser Tabelle zusätzliche Informationen, um Versionen der Zuordnung und Versionen des Modells zu korrelieren, wenn der zugehörige Datensatz geändert wird.

Ich habe nicht die hat-viele-Through Funktion von paper_trail verwendet, aber ich habe es für Objekte ohne Verbände verwendet, und fanden es sehr gut und einfach zu implementieren.

Um eine Textdatei protokollieren sowie diese Datenbank Papier-Trail können Sie paper_trail's diff features in einem after_save Rückruf verwenden.

Verwandte Themen