2009-05-14 11 views
54

Se si dispone di colonne DB created_at e updated_at, Rails imposterà automaticamente tali valori quando si crea e si aggiorna un oggetto modello. C'è un modo per salvare il modello senza toccare quelle colonne?C'è un modo per evitare di aggiornare automaticamente i campi di data e ora di Rails?

Sto introducendo alcuni dati legacy e vorrei impostare quei valori dai valori corrispondenti 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.

Ovviamente potrei semplicemente denominare le colonne del modello Rails in modo diverso per impedirlo, ma dopo che i dati sono stati importati, voglio che Rails esegua il suo timestamp automatico.

risposta

66

Fate questo in una migrazione o in un task rake (o in the new database seeds se siete su rotaie 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 

Si può tranquillamente impostare created_at e updated_at manualmente, Rails non si lamenterà .

Nota: Questo funziona anche su singoli modelli, ad es. User.record_timestamps = false

+3

Puoi persino inserire questo metodo in un metodo, ad es. 'def without_timestamps vecchio = ActiveRecord :: Base.record_timestamps ActiveRecord :: Base.record_timestamps = false iniziare resa garantire ActiveRecord :: Base.record_timestamps = vecchio fine FINE' – nonrectangular

+1

Abbiamo bisogno di ripristinare di nuovo a 'true', anche quando l'esecuzione di scrips o codice all'interno della console? – oldergod

+2

Penso che http://stackoverflow.com/a/37193298/1214748 sia molto meglio. Non lo spegne globalmente per l'intera applicazione – maschwenk

28

È possibile impostare la seguente all'interno della migrazione:

ActiveRecord::Base.record_timestamps = false 

O altenatively utilizzare update_all:

update_all (aggiornamenti, condizioni = nil, opzioni = {})

Aggiorna tutti i record con dettagli forniti se corrispondono a un set di condizioni fornito, limiti e ordine ca n anche essere fornito. Questo metodo crea una singola istruzione SQL UPDATE e invia direttamente al database. Lo standard non crea un'istanza dei modelli coinvolti e non attiva i callback del record attivo .

3

Poiché si tratta di un'importazione di una volta, si potrebbe fare la seguente:

  1. Creare modello usando legacy_created_at e legacy_updated_at campi.
  2. Carica dati legacy. Mappare nei campi del modello come desiderato. È possibile utilizzare #save e in genere non preoccuparsi dell'utilizzo di update_all o simili e, se lo si desidera, è possibile utilizzare i callback.
  3. Creare una migrazione per rinominare le colonne su created_at e updated_at.
47

metodo update_column uso invece:

http://api.rubyonrails.org/classes/ActiveRecord/Persistence.html#method-i-update_column

update_column(name, value) 
# Updates a single attribute of an object, without calling save. 

convalida viene saltato.

I callback vengono saltati.

La colonna updated_at/updated_on non viene aggiornata se tale colonna è disponibile.

Genera un errore ActiveRecordError quando viene chiamato su nuovi oggetti o quando l'attributo nome è contrassegnato come readonly.

+0

Ricorda che per le colonne serializzate dovrai prima valutare il valore di te stesso. – Jared

2

Quando non è in un'importazione in blocco, è possibile eseguire l'override di should_record_timestamps? metodo sul modello per aggiungere nuovi controlli su quando aggiornare la colonna updated_at.

2

Mi piace usare un modulo mixin per disattivare temporaneamente time-stamping 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 è possibile utilizzarlo ovunque ne abbiate bisogno

class MyModel < ActiveRecord::Base 
    include WithoutTimestamps 

    def save_without_timestamps 
    without_timestamps do 
     save! 
    end 
    end 
end 

O solo un one fuori in questo modo:

m = MyModel.find(1) 
WithoutTimestamps.without_timestamps do 
    m.save! 
end 
+1

Solo un avvertimento, questo non è sicuro. Recentemente è stato morso da questo! – Slicedpan

2

riferimento alla altre risposte, ho trovato con mia grande sorpresa che la disattivazione 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 timestamp per tutti i modelli con

ActiveRecord::Base.record_timestamps = false 

(Posizione: modificando l'attributo created_at in una migrazione)

21

Rotaie 5 fornisce un modo conveniente per aggiornare un record senza aggiornamento è timestamp updated_at.

È sufficiente passare il touch:false durante l'aggiornamento del 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 
+0

Questo è di gran lunga il modo più pulito per spostare i record. –

7

In Rails 3+, per un singolo oggetto, impostare record_timestamps per l'oggetto piuttosto che classe. 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 toccare stato globale per il modello, e non si deve ricordarsi di ripristinare l'impostazione precedente in un blocco ensure.

Problemi correlati