2010-11-21 18 views
10

Tengo una aplicación donde me gustaría anular el comportamiento de destruir para muchos de mis modelos. El caso de uso es que los usuarios pueden tener una necesidad legítima de eliminar un registro en particular, pero eliminar la fila de la base de datos destruiría la integridad referencial que afecta a otros modelos relacionados. Por ejemplo, un usuario del sistema puede querer eliminar a un cliente con el que ya no hace negocios, pero las transacciones con ese cliente deben mantenerse.¿Cuál es la mejor manera de anular el comportamiento de destrucción de ActiveRecord de Rails?

Parece que tengo al menos dos opciones:

  1. Los datos duplicados en los modelos necesariamente desnormalización efectivamente mi modelo de datos para que los registros eliminados no afectarán a los datos relacionados.
  2. Anule el comportamiento de "destrucción" de ActiveRecord para hacer algo así como establecer un indicador que indique que el usuario "eliminó" el registro y use este indicador para ocultar el registro.

¿Echa falta una mejor manera?

La opción 1 me parece una idea horrible, aunque me encantaría escuchar argumentos en contra.

La opción 2 parece algo Rails-ish, pero me pregunto cuál es la mejor manera de manejarlo. ¿Debo crear mi propia clase padre que herede de ActiveRecord :: Base, anular el método de destrucción allí, y luego heredar de esa clase en los modelos donde deseo este comportamiento? ¿Debo también anular el comportamiento del buscador para que los registros marcados como eliminados no se devuelvan de forma predeterminada?

Si hiciera esto, ¿cómo manejaría los buscadores dinámicos? ¿Qué pasa con los ámbitos con nombre?

Respuesta

8

Si usted no está realmente interesado en ver los registros de nuevo, pero sólo se preocupan de que todavía existen los niños cuando los padres se destruye, el trabajo es simple: añadir a la :dependent => :nullifyhas_many llamada a establecer referencias a los padres a NULL automáticamente después de la destrucción, y enseñar la vista para tratar con esa referencia que falta. Sin embargo, esto solo funciona si está de acuerdo con no volver a ver la fila nunca más, es decir, ver esas transacciones muestra "[NO EXISTE MÁS]" bajo el nombre de la empresa.

Si haces quieren ver que los datos de nuevo, parece que lo que quiere no tiene nada que ver con la realidad destruir los registros, lo que significa que nunca tendrá que referirse a ellos de nuevo. Ocultar parece ser el camino a seguir.

En lugar de anular la destrucción, ya que en realidad no está destruyendo el registro, parece mucho más simple poner su comportamiento en un método hide que desencadena una bandera, como sugirió.

A partir de ahí, cada vez que desee enumerar estos registros y solo incluir registros visibles, una solución simple es incluir un alcance visible que no incluya registros ocultos, y no incluirlo cuando quiera encontrar ese específico, oculto grabar de nuevo Otra ruta es usar default_scope para ocultar registros ocultos y usar Model.with_exclusive_scope { find(id) } para levantar un registro oculto, pero recomendaría que no lo haga, ya que podría ser un problema serio para un desarrollador entrante, y fundamentalmente cambia lo que Model.all no devuelve en absoluto reflejar lo que sugiere la llamada al método.

entiendo el deseo de hacer que los controladores se ven como que están haciendo las cosas como rieles, pero cuando no estás realmente hacer las cosas como rieles, lo mejor es ser explícito al respecto, sobre todo cuando es realmente No es muy doloroso hacerlo.

+0

Gracias Matchu. Estás en lo correcto, necesito usar los datos otra vez, entonces anular no es lo que estoy buscando. Si bien la simplicidad del complemento de Ryan mencionado en su respuesta es atractiva, tu argumento para ser explícito sobre el comportamiento me convenció. Aprecio la respuesta. –

6

Escribí a plugin for this exact purpose, llamado paranoia. Tomé "prestada" la idea de acts_as_paranoid y básicamente reescribí AAP usando mucho menos código.

Cuando llama al destroy en un registro, en realidad no lo elimina. En su lugar, establecerá una columna deleted_at en su base de datos a la hora actual.

El archivo README en la página de GitHub debería ser útil para la instalación de & uso. Si no es así, házmelo saber y veré si puedo solucionarlo por ti.

Cuestiones relacionadas