Wie ich bestätigen "auf in Schienen zerstören
-
02-07-2019 - |
Frage
Auf Zerstörung einer erholsamen Ressource, ich will ein paar Dinge garantieren, bevor ich einer Operation zerstören, damit weitermachen? Grundsätzlich mag ich die Fähigkeit, die zerstören Operation zu stoppen, wenn ich feststelle, damit die Datenbank in einem ungültigen Zustand versetzen würde? Es gibt keine Validierung Rückrufe auf einem zerstören Betrieb, so wie kann man „validieren“, ob ein zerstören Betrieb angenommen werden sollte?
Lösung
Sie können eine Ausnahme auslösen, die Sie dann fangen. Rails Wraps löscht in einer Transaktion, die Fragen hilft.
Zum Beispiel:
class Booking < ActiveRecord::Base
has_many :booking_payments
....
def destroy
raise "Cannot delete booking with payments" unless booking_payments.count == 0
# ... ok, go ahead and destroy
super
end
end
Alternativ können Sie den before_destroy Rückruf verwenden. Dieser Callback wird normalerweise verwendet, abhängig Datensätze zu zerstören, aber Sie können stattdessen eine Ausnahme oder fügen Sie einen Fehler aus.
def before_destroy
return true if booking_payments.count == 0
errors.add :base, "Cannot delete booking with payments"
# or errors.add_to_base in Rails 2
false
# Rails 5
throw(:abort)
end
myBooking.destroy
wird nun return false, und myBooking.errors
auf Rückkehr aufgefüllt werden.
Andere Tipps
Nur eine Anmerkung:
Für Schienen 3
class Booking < ActiveRecord::Base
before_destroy :booking_with_payments?
private
def booking_with_payments?
errors.add(:base, "Cannot delete booking with payments") unless booking_payments.count == 0
errors.blank? #return false, to not destroy the element, otherwise, it will delete.
end
Es ist das, was ich tat, mit Rails 5:
before_destroy do
cannot_delete_with_qrcodes
throw(:abort) if errors.present?
end
def cannot_delete_with_qrcodes
errors.add(:base, 'Cannot delete shop with qrcodes') if qrcodes.any?
end
Die Active Verbände has_many und has_one ermöglicht eine abhängige Option, die sicher zugehörige Tabellenzeilen gelöscht werden auf Lösch machen wird, aber dies ist in der Regel Ihre Datenbank sauber eher zu halten, als es von ungültig zu verhindern.
Sie können die zerstören wickeln Aktion in einer "if" Anweisung in der Steuerung:
def destroy # in controller context
if (model.valid_destroy?)
model.destroy # if in model context, use `super`
end
end
Dabei steht valid_destroy? ist eine Methode auf Ihrer Modellklasse, die true zurückgibt, wenn die Bedingungen für die Zerstörung eines Datensatzes erfüllt sind.
ein Verfahren wie diese zu haben wird auch Sie die Anzeige der Löschoption für den Benutzer zu verhindern - was die Benutzerfreundlichkeit verbessern, da der Benutzer nicht in der Lage sein, eine illegale Operation auszuführen.
beenden ich von hier aus unter Verwendung von Code bis zu einer can_destroy Überschreibung auf Active zu erstellen: https://gist.github.com/andhapp/1761098
class ActiveRecord::Base
def can_destroy?
self.class.reflect_on_all_associations.all? do |assoc|
assoc.options[:dependent] != :restrict || (assoc.macro == :has_one && self.send(assoc.name).nil?) || (assoc.macro == :has_many && self.send(assoc.name).empty?)
end
end
end
Dies hat den zusätzlichen Vorteil, es trivial zur Herstellung eine Löschtaste auf dem ui aus- / eingeblendet
Sie können auch den before_destroy Rückruf verwenden, um eine Ausnahme zu machen.
Ich habe diese Klassen oder Modelle
class Enterprise < AR::Base
has_many :products
before_destroy :enterprise_with_products?
private
def empresas_with_portafolios?
self.portafolios.empty?
end
end
class Product < AR::Base
belongs_to :enterprises
end
Wenn Sie nun ein Unternehmen löschen dieser Prozess, wenn es bestätigt Produkte mit Unternehmen verbunden sind, . Hinweis: Sie müssen schreiben diese in der Spitze der Klasse, um es zu bestätigen ersten
Mit Active Kontext Validierung in Rails 5.
class ApplicationRecord < ActiveRecord::Base
before_destroy do
throw :abort if invalid?(:destroy)
end
end
class Ticket < ApplicationRecord
validate :validate_expires_on, on: :destroy
def validate_expires_on
errors.add :expires_on if expires_on > Time.now
end
end
Ich hatte gehofft, dass dies so geöffnet unterstützt würde ich ein Schienen Problem zu erhalten hinzugefügt: