Se si hanno colonne DB updated_at
e updated_at
Rails, questi verranno automaticamente impostati quando si crea e si aggiorna un object modello. C’è un modo per salvare il modello senza toccare quelle colonne?
Sto introducendo alcuni dati legacy e vorrei impostare quei valori dai corrispondenti valori nei campi di dati legacy (con nomi diversi). Sto trovando quando li ho impostati sul modello e poi salvando il modello, Rails sembra sovrascrivere i valori in entrata.
Naturalmente potrei semplicemente nominare le colonne del modello Rails in modo diverso per impedirlo, ma dopo che i dati sono stati importati, voglio che Rails faccia il suo timestamp automatico.
Esegui questa operazione in una migrazione o in un’attività di rake (o nei nuovi seed del database se ti trovi su ringhiere di bordo):
ActiveRecord::Base.record_timestamps = false begin run_the_code_that_imports_the_data ensure ActiveRecord::Base.record_timestamps = true # don't forget to enable it again! end
Puoi tranquillamente impostare created_at
e updated_at
manualmente, Rails non si lamenterà.
Nota: funziona anche su singoli modelli, ad es. User.record_timestamps = false
utilizzare invece il metodo update_column:
http://api.rubyonrails.org/classs/ActiveRecord/Persistence.html#method-i-update_column
update_column(name, value) # Updates a single attribute of an object, without calling save.
La convalida viene saltata.
I callback vengono saltati.
La colonna updated_at / updated_on non viene aggiornata se tale colonna è disponibile.
Solleva un object ActiveRecordError quando viene richiamato un nuovo object o quando l’attributo name è contrassegnato come readonly.
Puoi impostare quanto segue all’interno della tua migrazione:
ActiveRecord::Base.record_timestamps = false
In alternativa, usa update_all:
update_all (updates, conditions = nil, options = {})
Aggiorna tutti i record con i dettagli forniti se corrispondono a una serie di condizioni fornite, i limiti e l’ordine possono anche essere forniti. Questo metodo crea una singola istruzione SQL UPDATE e la invia direttamente al database. Non crea un’istanza dei modelli coinvolti e non triggers i callback di Active Record.
Rails 5 fornisce un modo conveniente per aggiornare un record senza aggiornare il timestamp updated_at
.
Devi solo passare il touch:false
mentre aggiorni il tuo record.
>> user = User.first >> user.updated_at => Thu, 28 Apr 2016 20:01:57 IST +05:30 >> user.name = "Jose" >> user.save(touch: false) => true >> user.updated_at => Thu, 28 Apr 2016 20:01:57 IST +05:30
In Rails 3+, per un singolo object, imposta record_timestamps
per l’object piuttosto che per la class. Vale a dire,
>> user = User.first >> user.updated_at => Tue, 12 Apr 2016 22:47:51 GMT +00:00 >> user.name = "Jose" => "Jose" >> user.record_timestamps = false >> user.save => true >> user.updated_at => Tue, 12 Apr 2016 22:47:51 GMT +00:00 >> User.record_timestamps => true
In questo modo, non si tocca lo stato globale per il modello e non è necessario ricordare di ripristinare l’impostazione precedente in un blocco di ensure
.
Poiché si tratta di un’importazione una tantum, è ansible effettuare le seguenti operazioni:
legacy_created_at
e legacy_updated_at
. #save
e generalmente non preoccuparti di usare update_all
o simili, e puoi usare callback se lo desideri. created_at
e updated_at
. Quando non è in un’importazione in blocco, puoi sostituire i must_record_timestamps? metodo sul modello per aggiungere nuovi controlli su quando aggiornare la colonna updated_at.
Mi piace usare un modulo mixin per distriggersre temporaneamente la marcatura temporale in un blocco:
module WithoutTimestamps def without_timestamps old = ActiveRecord::Base.record_timestamps ActiveRecord::Base.record_timestamps = false begin yield ensure ActiveRecord::Base.record_timestamps = old end end end
Quindi puoi usarlo ovunque ti serva
class MyModel < ActiveRecord::Base include WithoutTimestamps def save_without_timestamps without_timestamps do save! end end end
O solo un one-off come questo:
m = MyModel.find(1) WithoutTimestamps.without_timestamps do m.save! end
Facendo riferimento ad altre risposte, ho scoperto con sorpresa che la distriggerszione di timestamp per un singolo modello, come in:
User.record_timestamps = false
ha funzionato per il mio database di sviluppo, ma non sul mio database di pre-produzione, che gira su un server diverso. Tuttavia funziona se disattivo i timestamp per tutti i modelli con
ActiveRecord::Base.record_timestamps = false
(Situazione: modifica dell’attributo created_at in una migrazione)
Oppure, per la sicurezza dei thread, vedere: http://www.hungryfools.com/2007/07/turning-off-activerecord-timestamp.html
Non ero in grado di far cambiare il flag ActiveRecord::Base.record_timestamps
, e l’unico modo funzionante è usare ActiveRecord::Base.no_touching {}
:
ActiveRecord::Base.no_touching do Project.first.touch # does nothing Message.first.touch # does nothing end Project.no_touching do Project.first.touch # does nothing Message.first.touch # works, but does not touch the associated project end
Preso da qui .
Ciò è molto utile per le attività rake in cui è necessario sovrascrivere alcune proprietà di modelli profondamente correlati e non si deve preoccupare dei callback interni, mentre gli utenti si basano su attributi created_at
o updated_at
o vengono utilizzati come colonne di ordinamento.