Risposte:
L'helper timestamp è disponibile solo nel create_tableblocco. Puoi aggiungere queste colonne specificando manualmente i tipi di colonna:
class AddTimestampsToUser < ActiveRecord::Migration
def change_table
add_column :users, :created_at, :datetime, null: false
add_column :users, :updated_at, :datetime, null: false
end
end
Sebbene ciò non abbia la stessa sintassi concisa del add_timestampsmetodo sopra specificato, Rails continuerà a trattare queste colonne come colonne timestamp e aggiornerà i valori normalmente.
rails g migration AddTimestampsToUser created_at:datetime updated_at:datetime- un collegamento per generare la migrazione sopra.
PG::NotNullViolation: ERROR: column "created_at" contains null value perché la mia tabella contiene già dati che violano il vincolo non nullo. Qual è il modo migliore per farlo che rimuovere inizialmente il contrappunto non nullo e poi aggiungerlo in seguito?
add_column :users, :updated_at, :datetime, null: false, default: Time.zone.now. Time.zone.nowè solo un esempio, dovresti usare qualunque valore abbia senso per la tua logica.
Le migrazioni sono solo due metodi di classe (o metodi di istanza in 3.1): upe down(e talvolta un changemetodo di istanza in 3.1). Vuoi che le tue modifiche entrino nel upmetodo:
class AddTimestampsToUser < ActiveRecord::Migration
def self.up # Or `def up` in 3.1
change_table :users do |t|
t.timestamps
end
end
def self.down # Or `def down` in 3.1
remove_column :users, :created_at
remove_column :users, :updated_at
end
end
Se sei in 3.1, puoi anche usare change(grazie Dave):
class AddTimestampsToUser < ActiveRecord::Migration
def change
change_table(:users) { |t| t.timestamps }
end
end
Forse stai confondendo def change, def change_tablee change_table.
Consulta la guida alla migrazione per ulteriori dettagli.
changemetodo, anche se in questo caso, non il problema :)
changevale la pena menzionare quindi aggiungerò anche quello.
Il tuo codice originale è molto vicino alla destra, devi solo usare un nome di metodo diverso. Se si utilizza Rails 3.1 o versioni successive, è necessario definire un changemetodo anziché change_table:
class AddTimestampsToUser < ActiveRecord::Migration
def change
add_timestamps(:users)
end
end
Se si utilizza una versione precedente, è necessario definire upe downmetodi anziché change_table:
class AddTimestampsToUser < ActiveRecord::Migration
def up
add_timestamps(:users)
end
def down
remove_timestamps(:users)
end
end
La risposta di @utente1899434 è dovuta al fatto che una tabella "esistente" qui potrebbe significare una tabella con record già presenti, record che potresti non voler eliminare. Pertanto, quando si aggiungono i timestamp con null: false, che è l'impostazione predefinita e spesso auspicabile, i record esistenti non sono tutti validi.
Ma penso che la risposta possa essere migliorata, combinando i due passaggi in un'unica migrazione, e usando il metodo più semantico add_timestamps:
def change
add_timestamps :projects, default: Time.zone.now
change_column_default :projects, :created_at, nil
change_column_default :projects, :updated_at, nil
end
Potresti sostituire qualche altro timestamp DateTime.now, come se volessi invece creare / aggiornare i record preesistenti all'alba dei tempi.
Time.zone.nowè ciò che dovrebbe essere usato se vogliamo che il nostro codice rispetti il fuso orario corretto.
Time.zone.nowquale verrà restituita l'istanza di Time che viene creata quando viene eseguita la migrazione e utilizza tale tempo come predefinito. I nuovi oggetti non riceveranno una nuova istanza di Time.
class AddTimestampsToUser < ActiveRecord::Migration
def change
change_table :users do |t|
t.timestamps
end
end
end
Le trasformazioni disponibili sono
change_table :table do |t|
t.column
t.index
t.timestamps
t.change
t.change_default
t.rename
t.references
t.belongs_to
t.string
t.text
t.integer
t.float
t.decimal
t.datetime
t.timestamp
t.time
t.date
t.binary
t.boolean
t.remove
t.remove_references
t.remove_belongs_to
t.remove_index
t.remove_timestamps
end
http://api.rubyonrails.org/classes/ActiveRecord/ConnectionAdapters/Table.html
La risposta di Nick Davies è la più completa in termini di aggiunta di colonne timestamp a una tabella con dati esistenti. L'unico aspetto negativo è che rilancierà ActiveRecord::IrreversibleMigrationa db:rollback.
Dovrebbe essere modificato in questo modo per funzionare in entrambe le direzioni:
def change
add_timestamps :campaigns, default: DateTime.now
change_column_default :campaigns, :created_at, from: DateTime.now, to: nil
change_column_default :campaigns, :updated_at, from: DateTime.now, to: nil
end
change_column_defaultche non supporti frome toin quella versione?), Ma ho preso questa idea e ho creato up/downmetodi invece di un singolo changemetodo e ha funzionato come un fascino!
def change
add_timestamps :table_name
end
non sono sicuro di quando sia stato introdotto esattamente questo, ma in Rails 5.2.1 puoi farlo:
class AddTimestampsToMyTable < ActiveRecord::Migration[5.2]
def change
add_timestamps :my_table
end
end
per ulteriori informazioni, consultare " utilizzo del metodo di modifica " nei documenti sulle migrazioni dei record attivi.
, null: truedopo il:my_table
Ho fatto una semplice funzione che è possibile chiamare da aggiungere a ciascun tavolo (supponendo che si dispone di un database esistente) il created_at e updated_at campi:
# add created_at and updated_at to each table found.
def add_datetime
tables = ActiveRecord::Base.connection.tables
tables.each do |t|
ActiveRecord::Base.connection.add_timestamps t
end
end
add_timestamps (table_name, options = {}) pubblico
Aggiunge colonne timestamps (Created_at e Updated_at) a table_name. Le opzioni aggiuntive (come null: false) vengono inoltrate a #add_column.
class AddTimestampsToUsers < ActiveRecord::Migration
def change
add_timestamps(:users, null: false)
end
end
Le risposte prima sembrano corrette, tuttavia ho riscontrato problemi se la mia tabella contiene già delle voci.
Vorrei ottenere 'ERRORE: la colonna created_atcontiene nullvalori'.
Per risolvere, ho usato:
def up
add_column :projects, :created_at, :datetime, default: nil, null: false
add_column :projects, :updated_at, :datetime, default: nil, null: false
end
Ho quindi usato il gem migration_data per aggiungere il tempo per i progetti attuali sulla migrazione come:
def data
Project.update_all created_at: Time.now
end
Quindi tutti i progetti creati dopo questa migrazione verranno aggiornati correttamente. Assicurati che anche il server venga riavviato in modo che Rails ActiveRecordinizi a tracciare i timestamp sul record.
Molte risposte qui, ma posterò anche le mie perché nessuna delle precedenti ha funzionato davvero per me :)
Come alcuni hanno notato, #add_timestampspurtroppo aggiunge la null: falserestrizione, che renderà le vecchie righe invalide perché non hanno questi valori popolati. La maggior parte delle risposte qui suggerisce che abbiamo impostato un valore predefinito ( Time.zone.now), ma non mi piacerebbe farlo perché questi timestamp predefiniti per i vecchi dati non saranno corretti. Non vedo il valore nell'aggiunta di dati errati alla tabella.
Quindi la mia migrazione è stata semplicemente:
class AddTimestampsToUser < ActiveRecord::Migration
def change_table
add_column :projects, :created_at, :datetime
add_column :projects, :updated_at, :datetime
end
end
No null: false, nessun'altra restrizione. Le vecchie righe continueranno a essere valide con created_atas NULLe update_atas NULL(fino a quando non viene eseguito un aggiornamento alla riga). Le nuove righe saranno created_ate updated_atpopolate come previsto.
Il problema con la maggior parte delle risposte qui è che se per impostazione predefinita Time.zone.nowtutti i record avranno il tempo in cui la migrazione è stata eseguita come ora predefinita, il che probabilmente non è quello desiderato. In Rails 5 puoi invece usare now(). Ciò imposterà i timestamp per i record esistenti come l'ora di esecuzione della migrazione e l'ora di inizio della transazione di commit per i record appena inseriti.
class AddTimestampsToUsers < ActiveRecord::Migration
def change
add_timestamps :users, default: -> { 'now()' }, null: false
end
end
L'utilizzo Time.currentè un buon stile https://github.com/rubocop-hq/rails-style-guide#timenow
def change
change_table :users do |t|
t.timestamps default: Time.current
t.change_default :created_at, from: Time.current, to: nil
t.change_default :updated_at, from: Time.current, to: nil
end
end
o
def change
add_timestamps :users, default: Time.current
change_column_default :users, :created_at, from: Time.current, to: nil
change_column_default :users, :updated_at, from: Time.current, to: nil
end
Questo è semplice per aggiungere il timestamp nella tabella esistente.
class AddTimeStampToCustomFieldMeatadata < ActiveRecord::Migration
def change
add_timestamps :custom_field_metadata
end
end
Sembra una soluzione pulita in Rails 5.0.7 (scoperto il metodo change_column_null):
def change
add_timestamps :candidate_offices, default: nil, null: true
change_column_null(:candidate_offices, :created_at, false, Time.zone.now)
change_column_null(:candidate_offices, :created_at, false, Time.zone.now)
end
Sono su Rails 5.0 e nessuna di queste opzioni ha funzionato.
L'unica cosa che funzionava era usare il tipo per essere: timestamp e non: datetime
def change
add_column :users, :created_at, :timestamp
add_column :users, :updated_at, :timestamp
end
Ho riscontrato lo stesso problema su Rails 5 durante il tentativo di utilizzo
change_table :my_table do |t|
t.timestamps
end
Sono stato in grado di aggiungere manualmente le colonne timestamp con il seguente:
change_table :my_table do |t|
t.datetime :created_at, null: false, default: DateTime.now
t.datetime :updated_at, null: false, default: DateTime.now
end