12

Als Beispiel für die kreisförmige dependent: :destroy Ausgabe:Ist ein Circular Rails 4 abhängig:: Workaround zu zerstören?

class User < ActiveRecord::Base 
    has_one: :staff, dependent: :destroy 
end 

class Staff < ActiveRecord::Base 
    belongs_to :user, dependent: :destroy 
end 

Wenn ich user.destroy nennen, sollte die zugehörige staff auch zerstört werden. Umgekehrt sollte das Aufrufen von staff.destroy das zugehörige user ebenfalls zerstören.

Dies funktionierte hervorragend in Rails 3.x, aber das Verhalten in Rails 4.0 geändert (und weiter in 4.1), so dass eine Schleife bildet und schließlich erhalten Sie einen Fehler, "Stack-Level zu tief." Eine offensichtliche Problemumgehung besteht darin, einen benutzerdefinierten Rückruf zu erstellen, der before_destroy oder after_destroy verwendet, um die zugeordneten Objekte manuell zu zerstören, statt den dependent: :destroy-Mechanismus zu verwenden. Selbst in der issue in GitHub opened for this Situation hatten einige Leute diese Problemumgehung empfohlen.

Leider kann ich diese Problemumgehung nicht einmal zur Arbeit bekommen. Das ist, was ich habe:

class User < ActiveRecord::Base 
    has_one: :staff 

    after_destroy :destroy_staff 

    def destroy_staff 
    staff.destroy if staff and !staff.destroyed? 
    end 
end 

Der Grund, warum dies nicht der Fall funktioniert, dass staff.destroyed?false immer wieder. Es bildet also einen Kreislauf.

+0

haben Sie diese Logik für beide Modelle implementiert, wie Jken13579 vorschlägt? – xlembouras

+0

@xlembouras, habe es nicht versucht, aber ich bin mir ziemlich sicher, es wird nicht funktionieren. Ich werde es irgendwann diese Woche versuchen, nur um sicher zu gehen. Ich habe unten geschrieben, warum es nicht funktioniert. –

+0

@at. Hast du Glück mit meiner Antwort? –

Antwort

2

Ich sah mich auch diesem Problem gegenüber und kam zu einer Lösung, die nicht schön ist, aber funktioniert. Im Wesentlichen würden Sie einfach eine destroy_user verwenden, die destroy_staff ähnlich ist.

class User < ActiveRecord::Base 
    has_one: :staff 

    after_destroy :destroy_staff 

    def destroy_staff 
    staff.destroy if staff && !staff.destroyed? 
    end 
end 

class Staff < ActiveRecord::Base 
    belongs_to :user 

    after_destroy :destroy_user 

    def destroy_user 
    user.destroy if user && !user.destroyed? 
    end 
end 
+0

Seltsam, stackoverflow hat meinen Posteingang nicht aktualisiert, dass Sie eine Antwort hatten. Ich werde es versuchen, aber ich bin sicher, es wird nicht funktionieren. Ich habe so viele Variationen ausprobiert. Im Wesentlichen alle ".destroyed?" - Aufrufe *** immer *** gibt in Rails 4.1 false zurück, wenn sie von einem 'before_destroy' oder' after_destroy' Callback aufgerufen werden. –

+0

Ich hoffe, es funktioniert für Sie in Rail 4.1, weil ich es nur in Rails 4.0 getestet habe, obwohl ich denke, dass das keinen Unterschied machen sollte. –

4

Wenn eine Seite des Zyklus nur, dass ein Rückruf, Sie eines der dependent: :destroy mit dependent: :delete

class User < ActiveRecord::Base 
    # delete prevents Staff's :destroy callback from happening 
    has_one: :staff, dependent: :delete 
    has_many :other_things, dependent: :destroy 
end 

class Staff < ActiveRecord::Base 
    # use :destroy here so that other_things are properly removed 
    belongs_to :user, dependent: :destroy 
end 

Arbeitete groß für mich ersetzen kann, solange eine Seite nicht andere braucht Rückrufe zu feuern.