ActiveRecord#save_only_valid_attributes
-
09-06-2019 - |
Domanda
Sto cercando una variazione sul #save
Metodo che salverà solo gli attributi che non hanno errori ad essi collegati.Pertanto, un modello può essere aggiornato senza essere valido nel complesso e ciò impedirà comunque di salvare i dati non validi nel database.
Per "attributi validi" intendo quegli attributi che danno zero quando si chiama @model_instance.errors.on(:attribute)
Qualcuno ha un'idea di come realizzare questo?
Finora, ho quanto segue:
def save_valid_attributes
valid?
update_atrtibutes attributes.inject({}){|k, v, m| m[k] = v unless errors_on(k.to_sym); m}
end
Funziona se non viene eseguita alcuna elaborazione sull'incarico, cosa che nel mio caso esiste.Ad esempio, ho una colonna del database "start_date" e due metodi definiti:
def nice_start_date=(startdate)
self.start_date = Chronic.parse(startdate) || startdate
end
def nice_start_date
self.start_date.to_s
end
Questi due metodi mi consentono di analizzare correttamente le date immesse dall'utente utilizzando Chronic prima di salvare.Quindi, secondo modo per farlo, un attributo alla volta:
def save_valid_attributes(attrib)
valid?
attrib.each{|(k,v)| send("${k}=", v); save; reload)
end
Il modello deve essere ricaricato ogni volta poiché, se una delle date non è valida e non viene salvata, impedirà il salvataggio di tutti gli ulteriori attributi.
Esiste un modo migliore per farlo?Sono sicuro che questo non sia un problema raro nel mondo Rails, semplicemente non riesco a trovare nulla nell'universo della conoscenza di Google.
Soluzione
Non sono sicuro di quanta fortuna avrai con questo senza troppi problemi.
Non importa quanto DRY, OO e semplice il tuo framework renda le cose (che è in questo caso - molto =) devi comunque ricordare che è in esecuzione davanti a un database relazionale standard, che ha commit atomici come uno dei suoi definendo caratteristiche.È progettato da zero per garantire che tutte le modifiche vengano applicate o nessuna.
In effetti supererai questa funzionalità standard con qualcosa che va al 100% contro il modo in cui rails + è stato progettato per funzionare.Ciò probabilmente porterà (come già detto) a dati incoerenti.
Avendolo detto ...è sempre possibile.Vorrei cercare di eseguire la convalida manuale degli attributi che ti interessano e quindi utilizzare il metodo integrato object.update_attribute_with_validation_skipping.
Buona fortuna!
Altri suggerimenti
Puoi sovrascrivere #save
come questo:
def save
errors.each do |attr, msg|
send("#{attr}=", send("#{attr}_was"))
end
super
end
Ciò ripristinerà tutti gli attributi con errori associati al loro valore originale.