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?

War es hilfreich?

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:

https://github.com/rails/rails/issues/32376

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top