C’è un modo per evitare di aggiornare automaticamente i campi di timestamp di Rails?

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:

  1. Creare un modello usando i campi legacy_created_at e legacy_updated_at .
  2. Carica dati legacy. Mappare nei campi del modello come desiderato. Puoi usare #save e generalmente non preoccuparti di usare update_all o simili, e puoi usare callback se lo desideri.
  3. Creare una migrazione per rinominare le colonne su 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)

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.