Risposte:
L'helper timestamp è disponibile solo nel create_table
blocco. 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_timestamps
metodo 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): up
e down
(e talvolta un change
metodo di istanza in 3.1). Vuoi che le tue modifiche entrino nel up
metodo:
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_table
e change_table
.
Consulta la guida alla migrazione per ulteriori dettagli.
change
metodo, anche se in questo caso, non il problema :)
change
vale 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 change
metodo anziché change_table
:
class AddTimestampsToUser < ActiveRecord::Migration
def change
add_timestamps(:users)
end
end
Se si utilizza una versione precedente, è necessario definire up
e down
metodi 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.now
quale 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::IrreversibleMigration
a 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_default
che non supporti from
e to
in quella versione?), Ma ho preso questa idea e ho creato up/down
metodi invece di un singolo change
metodo 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: true
dopo 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_at
contiene null
valori'.
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 ActiveRecord
inizi 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_timestamps
purtroppo aggiunge la null: false
restrizione, 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_at
as NULL
e update_at
as NULL
(fino a quando non viene eseguito un aggiornamento alla riga). Le nuove righe saranno created_at
e updated_at
popolate come previsto.
Il problema con la maggior parte delle risposte qui è che se per impostazione predefinita Time.zone.now
tutti 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