2012-04-06 25 views
6

¿Hay alguna forma de comprobar, dentro de un gancho before_destroy, qué objeto (clase) se llama destroy?has_many a través de la asociación dependiente destruir bajo condición de quién llamó destroy

En el siguiente ejemplo, cuando se destruye un patient, también lo es su appointments (que es lo que quiero); sin embargo, no quiero permitir que se destruya physician si hay algún appointments asociado con ese physician.

De nuevo, ¿hay alguna manera de hacer tal control en la devolución de llamada before_destory? Si no, ¿hay alguna otra manera de lograr este "control de destrucción" basado en la "dirección" de la llamada (es decir, según quién llamó)?

class Physician < ActiveRecord::Base 
    has_many :appointments, dependent: :destroy 
    has_many :patients, through: :appointments 
end 


class Patient < ActiveRecord::Base 
    has_many :appointments, dependent: :destroy 
    has_many :physicians, through: :appointments 
end 


class Appointment < ActiveRecord::Base 
    belongs_to :patient 
    belongs_to :physician 

    before_destroy :ensure_not_referenced_by_anything_important 

    private 

    def ensure_not_referenced_by_anything_important 
    unless patients.empty? 
     errors.add(:base, 'This physician cannot be deleted because appointments exist.') 
     false 
    end 
    end 
end 

Respuesta

11

Sólo decir:

class Physician < ActiveRecord::Base 
    has_many :appointments, dependent: :restrict_with_exception 
    has_many :patients, through: :appointments 
end 

Nota del dependent: :restrict_with_exception. Esto hará que Active Record se rehúse a destruir los registros de un médico que tengan registros de citas asociados.

Ver the API docs y the association basics guide.

+0

[ ': restrict' está desfasada] (https://github.com/rails/rails/commit/5ad79989ef0a015fd22cfed90b2e8a56881e6c36#diff-5870816b49b90e43340607bb11ed2514R91) Ago 10 de 2012 en una rama destinada a' 4'rieles. [La guía * basic * de la asociación también se actualizó] (https://github.com/rails/rails/commit/a63fc94aa3689f1e781ac51411ec79a81c011d8a). ': restrict_with_exception' proporciona la misma funcionalidad que': restrict'; también hay otra opción similar, ': restrict_with_error', que causa que se agregue un error al propietario si hay un objeto asociado. – user664833

15

Tenga en cuenta que dependent: :destroy en una relación has_many :through sólo elimina la asociación y no el registro asociado (es decir se eliminarán los registros de unirse, pero los registros asociados no lo hará). Por lo tanto, si elimina un patient, solo eliminará el appointment y no el physician. Lea la explicación detallada en the API docs.

He pegado los párrafos pertinentes a continuación.

¿Qué se elimina?

Existe un riesgo potencial aquí: las asociaciones has_and_belongs_to_many y has_many :through tienen registros en las tablas de combinación, así como los registros asociados. Entonces, cuando llamamos a uno de estos métodos de eliminación, ¿qué debería eliminarse exactamente?

La respuesta es que se supone que la eliminación en una asociación consiste en eliminar el vínculo entre el propietario y los objetos asociados, en lugar de necesariamente los objetos asociados. Por lo tanto, con has_and_belongs_to_many y has_many :through, los registros de combinación se eliminarán, pero los registros asociados no.

Esto tiene sentido si se piensa en ello: si tuviera que llamar post.tags.delete(Tag.find_by_name('food')) le gustaría que la etiqueta food a ser no enlazados desde el post, más que por la propia etiqueta sea retirado de la base de datos.

+0

¡Gran explicación, gracias! Estaba teniendo dificultades para determinar si dependiente: destruir destruía la asociación y el registro del otro lado. – Arel

+0

Esto parece una respuesta completa, sin embargo, lo configuré como dijiste y cuando intento eliminar un paciente (usando el administrador de rieles), el médico también se retira. –

Cuestiones relacionadas