en la destrucción de un recurso de descanso, quiero garantizar un par de cosas antes de permitir una operación de destruir a continuar? Básicamente, quiero la capacidad de detener la operación de destrucción si noto que al hacerlo colocaría la base de datos en un estado inválido. No hay devoluciones de llamada de validación en una operación de destrucción, entonces, ¿cómo se puede "validar" si se debe aceptar una operación de destrucción?¿Cómo 'validar' en dañarán en los carriles
Respuesta
Puede provocar una excepción que luego se captura. Rails wraps elimina en una transacción, lo que ayuda a las cosas.
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, puede utilizar la devolución de llamada before_destroy. Esta devolución de llamada normalmente se usa para destruir registros dependientes, pero 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 volverá falso, y myBooking.errors
se rellenarán en la declaración.
Um, ¿qué pasa con sólo comprobar la asociación booking_payments que debe ser definido en ese modelo en lugar de llamar BookingPayment .count, lo que lleva a un código feo? –
He editado mi respuesta en consecuencia. Lo siento, saqué esto de un código antiguo ... –
Ten en cuenta que cuando ahora dice "... vale, sigue adelante y destruye", necesitas poner "super", así que el método de destrucción original se llama realmente. –
También puede utilizar la devolución de llamada before_destroy a lanzar una excepción.
Las asociaciones de ActiveRecord has_many y has_one permiten una opción dependiente que asegurará que las filas de la tabla relacionadas se eliminen en delete, pero esto generalmente es para mantener su base de datos limpia en lugar de evitar que no sea válida.
+1 para "\ _" no se dio cuenta de que era una opción en SO – ahsteele
Otra forma de tener en cuenta los guiones bajos, si son parte de un nombre de función o similar, es envolverlos en puntos reutilizables. Eso se mostrará luego como código, 'like_so'. –
Puede envolver la acción destruir 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
Dónde valid_destroy? es un método en su clase de modelo que devuelve verdadero si se cumplen las condiciones para destruir un registro.
Tener un método como este también le permitirá evitar que la pantalla de la opción de borrar para el usuario - que mejorarán la experiencia de usuario que el usuario no será capaz de realizar una operación ilegal.
Bucle infinito, ¿alguien? – jenjenut233
buena captura, pero suponía que este método está en el controlador, difiriendo el modelo. Si estuviera en el modelo definitivamente causaría problemas –
jeje, perdón por que ... Veo lo que quiere decir, acabo de ver "método en su clase de modelo" y rápidamente pensé "uh oh", pero tiene razón - destruir en el controlador, eso funcionaría bien. :) – jenjenut233
sólo una nota:
Para carriles 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
Un problema con este enfoque es que la devolución de llamada before_destroy parece llamarse * después de * todos los booking_payments han sido destruidos. – sunkencity
Boleto relacionado: https://github.com/rails/rails/issues/3458 @sunkencity puede declarar before_destroy antes de la declaración de la asociación para evitarlo temporalmente. – lulalala
que terminó usando el código de aquí para crear una anulación can_destroy 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 añadido beneficio de lo que es trivial para ocultar/mostrar un botón de borrar en la interfaz de usuario
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 este proceso valida si hay productos asociados con empresas Nota: Tienes que escribir esto en la parte superior de la clase con el fin de validarla primero.
Es lo que hice con los carriles 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
Este es un buen artículo que explica este comportamiento en Rails 5: http://blog.bigbinary.com/2016/02/13/rails-5-does-not-halt-callback-chain-when-false-is- returned.html –
Uso ActiveRecord validación de contexto en los carriles 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
- 1. validar y actualizar único atributo carriles
- 2. default_scope en los carriles 3
- 3. Asociación privada en los carriles
- 4. Validar los dicts en Python
- 5. Cómo marcar los campos en los carriles errores de validación
- 6. Cómo cargar la configuración en el arranque en los carriles?
- 7. rubí en los carriles javascript_include_tag: por defecto
- 8. link_to con params jquery en los carriles
- 9. accesorios con las asociaciones en los carriles
- 10. Validar singularidad de asociación en
- 11. read_inheritable_attribute indefinido en los carriles 3.2.8
- 12. validaciones de formato múltiple en los carriles
- 13. enormes migraciones de datos en los carriles
- 14. modelos de actualización en los carriles/migraciones
- 15. de anidamiento: JSON incluir en los carriles
- 16. conexión DB múltiple en los carriles
- 17. Ruta de análisis en los carriles
- 18. conexión de base múltiple en los carriles
- 19. definición constante dinámica en los carriles
- 20. de nomenclatura columnas booleanas en los carriles
- 21. f.hidden_field en los carriles de 3,2
- 22. ¿Cómo puedo usar los carriles auxiliares "distance_of_time_in_words" en edad de rubíes llano (no carriles)
- 23. Cómo añadir 10 días a la hora en los carriles
- 24. ¿Cómo enviar de vuelta js.haml en los carriles
- 25. ¿Cómo se prueba caducidad de cookies en los carriles rspec
- 26. Cómo asignar condicionalmente ActionController :: Base.session en los carriles 2.3.3
- 27. elementos Cómo hacer un pedido incluidos en los carriles 3
- 28. Cómo establecer una matriz multidimensional en sesión con los carriles
- 29. cómo ejecutar SQL con parámetros arbitrarios en los carriles
- 30. Cómo validar colecciones en Maps
relacionadas: http://stackoverflow.com/questions/5520320/validate-before-destroy –