Visualizzazione dei risultati da 1 a 8 su 8

Discussione: [Rails] before_destroy

  1. #1

    [Rails] before_destroy

    Ciao, avrei bisogno di una mano a capire come impedire la cancellazione di un record che abbia delle "dipendenze" associate.

    Mettiamo di avere una categoria_prodotto con dei prodotti associati; io vorrei poter generare un errore da mostrare all'utente quando tento di cancellare una di queste categorie per cui sono effettivamente presenti dei prodotti.

    Come devo agire nel Model e nel Controller per ottenere tutto questo?

    So che il Model permette di utilizzare il callback "before_destroy" ma non riesco a capire dove e come esattamente eseguire la query di verifica e come poi visualizzare l'errore specifico all'utente nella view "index".

    Putroppo non riesco ancora, in generale, a districarmi bene tra quelle che sono le prerogative del Model e quelle invece del Controller.

    Grazie.

  2. #2

  3. #3
    Come devo agire nel Model e nel Controller per ottenere tutto questo?
    Innanzi tutto devi risolvere bene questo problema.
    Individuare le corrette competenzer è fondamentale.

    Come dice andrea, in questo caso il problema è competenza del modello.

    Ci sono diversi modi per risolvere questo problema, a seconda del livello di sicurezza che vuoi ottenere.
    Ecco due possibili soluzioni

    1. creare un nuovo metodo nel modello categoria, chiamato ad esempio destroyable?, che ritorni true o false a seconda che l'oggetto possa o meno essere distrutto.
    La logica condizionale dipende da te. nel tuo caso, potrebbe essere semplicemente la presenza o meno di record associati.

    Ogni qual volta vorrai cancellare un record, dovrai prima preoccuparti di chiamare il metodo destroyable? e verificare che restituisca true. In caso negativo, impedire la cancellazione.

    2. la seconda ipotesi delega meno alle assunzioni del programmatore e si occupa di validare ad un livello più bhasso i requisiti.
    Crea un'eccezione di tipo NotDestroyable che estenda ActiveRecordError.
    Poi inserisci un nuovo before_destroy ed all'interno controlla la presenza di record associati. In caso il risultato non sia vuoto, lancia l'eccezione.

    In questo modo il sistema interromperà immediatamente la cancellazione nel caso in cui esistano record associati. Ovviamente dovrai gestire nel modo corretto l'eccezione.

  4. #4
    Si certo, trattasi di integrità referenziale ma ... non trovo il punto specifico (tra i link che mi hai girato) ove trovare un esempio di ciò che ho bisogno.

    Ho provato a fare una cosa del genere:

    codice:
    before_destroy :removable?
    
      def removable?
       c = Product.find(:all, :conditions => ['product_category_id = ?',self[:id]]).collect
       if c.size > 0
         return false
       end
      end
    ma il return false non sembra sortire effetto, eppure facendo dei test se provo a stampare a video il risultato di "c.size > 0" nell'action "show" delle varie categorie, vedo correttamente i valori true/false.

    Aiuto

  5. #5
    Credo che il tuo ultimo post fosse riferito ad andrea.
    Ad ogni modo, ti segnalo che tutto quel pappocchio di codice che hai scritto si riassume semplicemente da

    codice:
    def removable?
     c = Product.find(:all, :conditions => ['product_category_id = ?',self[:id]]).collect
     if c.size > 0
       return false
     end
    end
    a

    codice:
    def removable?
      products.empty?
    end
    Quando sviluppi in Ruby, devi pensare in Ruby non tradurre da altri linguaggi.
    Il metodo removable? che ho scritto ritorna esattamente true se la categoria non ha prodotti, false altrimenti.

  6. #6
    Si mi riferivo ad Andrea in effetti.

    Con il tuo codice ora funziona, grazie.

    Si lo so hai ragione, ma venendo da PHP è dura cambiare completamente approccio.

    Non capisco come mai con "empty?" funzioni mentre valutando "c.size > 0" no.



    Grazie ancora.

  7. #7
    In ruby, ogni espressione ritorna come valore il valore dell'ultima espressione valutata.
    Nel tuo caso, utilizzi un if senza else. Quando il valore è maggiore di >, l'interprete non entra nella condizione ed il valore dell'ultima espressione valutata è nil. Il metodo quindi ritorna false or nil.

    Ritornare nil in un before callback equivale a ritornare false, ovvero interrompere l'elaborazione.

    Ci sono almeno 2 errori importanti in quel metodo:

    1. creare un metodo con ? che ritorni valori misti invece di true/false.
    2. passare un metodo che ritorna valori misti inconsapevolmente ad un callback

    Il risultato è, ovviamente, quello che tu stesso hai sperimentato.

  8. #8
    Ti ringrazio, sei stato molto esaustivo.

Permessi di invio

  • Non puoi inserire discussioni
  • Non puoi inserire repliche
  • Non puoi inserire allegati
  • Non puoi modificare i tuoi messaggi
  •  
Powered by vBulletin® Version 4.2.1
Copyright © 2024 vBulletin Solutions, Inc. All rights reserved.