2012-04-06 12 views
6

C'è un modo per verificare, all'interno di un hook before_destroy, quale oggetto (classe) chiama destroy?has_many tramite associazione dipendente da distruzione in condizione di chi ha chiamato destroy

Nell'esempio seguente, quando un patient viene eliminato, lo stesso vale per appointments (che è ciò che desidero); tuttavia non voglio permettere che un physician venga distrutto se ci sono appointments associati a quello physician.

Ancora, c'è un modo per effettuare tale controllo nella richiamata before_destory? In caso contrario, esiste un altro modo per eseguire questo "controllo di distruzione" in base alla "direzione" della chiamata (in base a chi ha chiamato)?

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 

risposta

11

Basta dire:

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

Annotare la dependent: :restrict_with_exception. Ciò farà sì che Active Record rifiuti di distruggere qualsiasi record di Medico che abbia associato i record degli Appuntamenti.

Vedere the API docs e the association basics guide.

+0

[ ': RESTRICT' è stata sconsigliata] (https://github.com/rails/rails/commit/5ad79989ef0a015fd22cfed90b2e8a56881e6c36#diff-5870816b49b90e43340607bb11ed2514R91) 10 AGOSTO 2012 in un ramo destinato a' 4' Rails. [Anche la guida * sulle basi dell'associazione * è stata aggiornata] (https://github.com/rails/rails/commit/a63fc94aa3689f1e781ac51411ec79a81c011d8a). ': restrict_with_exception' fornisce la stessa funzionalità di': restrict'; c'è anche un'altra opzione simile, ': restrict_with_error', che fa sì che venga aggiunto un errore al proprietario se c'è un oggetto associato. – user664833

15

noti che dependent: :destroy su un rapporto has_many :through cancella solo l'associazione e non il record associato (vale a dire i record unire verranno eliminati, ma i record associati non sarà). Pertanto, se elimini uno patient, verrà eliminato solo lo appointment e non lo physician. Leggi la spiegazione dettagliata in the API docs.

Ho incollato i paragrafi pertinenti di seguito.

Cosa viene eliminato?

C'è una potenziale trappola qui: le associazioni has_and_belongs_to_many e has_many :through hanno record nelle tabelle di join, nonché i record associati. Quindi, quando chiamiamo uno di questi metodi di cancellazione, che cosa dovrebbe essere cancellato esattamente?

La risposta è che si presume che l'eliminazione su un'associazione riguardi la rimozione del collegamento tra il proprietario e gli oggetti associati, piuttosto che necessariamente gli oggetti associati stessi. Quindi con has_and_belongs_to_many e has_many :through, i record di join verranno eliminati, ma i record associati no.

Questo ha un senso se si pensa a questo proposito: se si dovesse chiamare post.tags.delete(Tag.find_by_name('food')) si desidera che il tag food da scollegato dal post, piuttosto che per tag stesso di essere rimosso dal database.

+0

Ottima spiegazione, grazie! Ho avuto difficoltà a capire se dipendente: distruggi l'associazione cancellata e il record dall'altra parte. – Arel

+0

Questa sembra una risposta esauriente, tuttavia, l'ho impostato come hai detto tu e quando provo a eliminare un paziente (usando l'amministrazione delle rotaie), anche il medico viene rimosso. –

Problemi correlati