Pregunta

En la destrucción de un recurso rest, quiero garantizar un par de cosas antes de permitir una operación para destruir a continuar?Básicamente, quiero la capacidad para dejar de destruir la operación si se me nota que hacerlo pondría a la base de datos en un estado no válido?No hay ninguna validación de las devoluciones de llamada en destruir la operación, así que ¿cómo hace uno para "validar" si un destruir la operación debe ser aceptado?

¿Fue útil?

Solución

Puede provocar una excepción que luego de la captura.Rieles envuelve elimina en una transacción, lo que ayuda a la materia.

Por ejemplo:

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

Alternativamente, usted puede utilizar el before_destroy de devolución de llamada.Esta devolución de llamada se utiliza normalmente para destruir dependiente de registros, pero usted puede lanzar una excepción o agregar un error en su lugar.

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 ahora va a devolver false, y myBooking.errors se rellenará en el retorno.

Otros consejos

sólo una nota:

Para rails 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 lo que yo hice con Rieles de 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

El ActiveRecord asociaciones has_many y has_one permite un dependiente de la opción que asegúrese relacionado con las filas de la tabla se eliminan en eliminar, pero esto es por lo general para mantener su base de datos limpia en lugar de prevenirla de ser válido.

Usted puede ajustar el destruir la acción en un "if" en el controlador:

def destroy # in controller context
  if (model.valid_destroy?)
    model.destroy # if in model context, use `super`
  end
end

Donde valid_destroy? es un método en el modelo de clase que devuelve true si las condiciones para la destrucción de un registro que se cumplan.

Tener un método como este también te permitirá evitar que la pantalla de la opción eliminar para el usuario, lo que permitirá mejorar la experiencia del usuario como el usuario no será capaz de realizar una operación ilegal.

Terminé utilizando el código de aquí para crear una can_destroy reemplazar en activerecord: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

Esto tiene el beneficio añadido de lo que es trivial para ocultar/mostrar un botón de borrar en la interfaz de usuario

También puede utilizar el before_destroy de devolución de llamada para provocar una excepción.

Tengo estas clases o modelos

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

Ahora cuando se elimina una empresa de este proceso valida si hay productos asociados con las empresas Nota:Usted tiene que escribir esto en la parte superior de la clase con el fin de validar primero.

Usar ActiveRecord contexto de validación en 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

Tenía la esperanza de que esto sería compatible con lo abrí rails problema para obtener añadió:

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

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top