Antworten:
Der Zeitstempel-Helfer ist nur im create_table
Block verfügbar . Sie können diese Spalten hinzufügen, indem Sie die Spaltentypen manuell angeben:
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
Dies hat zwar nicht die gleiche knappe Syntax wie die add_timestamps
oben angegebene Methode, Rails behandelt diese Spalten jedoch weiterhin als Zeitstempelspalten und aktualisiert die Werte normal.
rails g migration AddTimestampsToUser created_at:datetime updated_at:datetime
- eine Verknüpfung zum Generieren der obigen Migration.
PG::NotNullViolation: ERROR: column "created_at" contains null value
da meine Tabelle bereits Daten enthält, die nicht gegen die Null-Einschränkung verstoßen. Gibt es eine bessere Möglichkeit, dies zu tun, als zuerst die Nicht-Null-Kontraint zu entfernen und sie später hinzuzufügen?
add_column :users, :updated_at, :datetime, null: false, default: Time.zone.now
. Time.zone.now
ist nur ein Beispiel, Sie sollten jeden Wert verwenden, der für Ihre Logik sinnvoll ist.
Migrationen sind nur zwei Klassenmethoden (oder Instanzmethoden in 3.1): up
und down
(und manchmal eine change
Instanzmethode in 3.1). Sie möchten, dass Ihre Änderungen in die up
Methode übernommen werden:
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
Wenn Sie in 3.1 sind, können Sie auch verwenden change
(danke Dave):
class AddTimestampsToUser < ActiveRecord::Migration
def change
change_table(:users) { |t| t.timestamps }
end
end
Vielleicht sind verwirrend Sie def change
, def change_table
und change_table
.
Weitere Informationen finden Sie im Migrationshandbuch .
change
jetzt die Methode, obwohl in diesem Fall nicht das Problem :)
change
ist eine Erwähnung wert, also werde ich das auch hinzufügen.
Ihr ursprünglicher Code befindet sich ganz in der Nähe von rechts. Sie müssen lediglich einen anderen Methodennamen verwenden. Wenn Sie Rails 3.1 oder höher verwenden, müssen Sie eine change
Methode definieren , anstatt change_table
:
class AddTimestampsToUser < ActiveRecord::Migration
def change
add_timestamps(:users)
end
end
Wenn Sie eine ältere Version verwenden, müssen Sie up
und down
Methoden definieren , anstatt change_table
:
class AddTimestampsToUser < ActiveRecord::Migration
def up
add_timestamps(:users)
end
def down
remove_timestamps(:users)
end
end
Die Antwort von @ user1899434 hat die Tatsache aufgegriffen, dass eine "vorhandene" Tabelle hier eine Tabelle mit bereits darin enthaltenen Datensätzen bedeuten kann, Datensätze, die Sie möglicherweise nicht löschen möchten. Wenn Sie also Zeitstempel mit null: false hinzufügen, was die Standardeinstellung ist und häufig wünschenswert ist, sind alle vorhandenen Datensätze ungültig.
Ich denke jedoch, dass die Antwort verbessert werden kann, indem die beiden Schritte zu einer Migration kombiniert werden und die semantischere Methode add_timestamps verwendet wird:
def change
add_timestamps :projects, default: Time.zone.now
change_column_default :projects, :created_at, nil
change_column_default :projects, :updated_at, nil
end
Sie können einen anderen Zeitstempel ersetzen, z DateTime.now
. B. wenn bereits vorhandene Datensätze zu Beginn der Zeit erstellt / aktualisiert werden sollen.
Time.zone.now
sollte verwendet werden, wenn unser Code der richtigen Zeitzone entsprechen soll.
Time.zone.now
der die beim Ausführen der Migration erstellte Zeitinstanz zurückgegeben wird und nur diese Zeit als Standard verwendet wird. Neue Objekte erhalten keine neue Zeitinstanz.
class AddTimestampsToUser < ActiveRecord::Migration
def change
change_table :users do |t|
t.timestamps
end
end
end
Verfügbare Transformationen sind
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
Die Antwort von Nick Davies ist die vollständigste, wenn es darum geht, einer Tabelle mit vorhandenen Daten Zeitstempelspalten hinzuzufügen. Sein einziger Nachteil ist , dass es anheben wird ActiveRecord::IrreversibleMigration
auf einem db:rollback
.
Es sollte so modifiziert werden, dass es in beide Richtungen funktioniert:
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
es wird nicht unterstützt from
und to
in dieser Version?), Aber ich nahm diese Idee und erstellte up/down
Methoden anstelle einer einzelnen change
Methode und es funktionierte wie ein Zauber!
def change
add_timestamps :table_name
end
Ich bin mir nicht sicher, wann genau dies eingeführt wurde, aber in Rails 5.2.1 können Sie dies tun:
class AddTimestampsToMyTable < ActiveRecord::Migration[5.2]
def change
add_timestamps :my_table
end
end
Weitere Informationen finden Sie unter " Verwenden der Änderungsmethode " in den Dokumenten zur aktiven Datensatzmigration.
, null: true
nach dem:my_table
Ich habe eine einfache Funktion erstellt, die Sie aufrufen können, um jeder Tabelle (vorausgesetzt, Sie haben eine vorhandene Datenbank) die Felder created_at und updated_at hinzuzufügen :
# 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 = {}) public
Fügt dem Tabellennamen Zeitstempelspalten (created_at und updated_at) hinzu. Zusätzliche Optionen (wie null: false) werden an #add_column weitergeleitet.
class AddTimestampsToUsers < ActiveRecord::Migration
def change
add_timestamps(:users, null: false)
end
end
Die Antworten zuvor scheinen richtig zu sein, aber ich hatte Probleme, wenn meine Tabelle bereits Einträge enthält.
Ich würde 'ERROR: Spalte created_at
enthält null
Werte' erhalten.
Um das Problem zu beheben, habe ich Folgendes verwendet:
def up
add_column :projects, :created_at, :datetime, default: nil, null: false
add_column :projects, :updated_at, :datetime, default: nil, null: false
end
Ich habe dann das Gem Migration_Data verwendet , um die Zeit für aktuelle Projekte für die Migration hinzuzufügen, z.
def data
Project.update_all created_at: Time.now
end
Dann werden alle nach dieser Migration erstellten Projekte korrekt aktualisiert. Stellen Sie sicher, dass auch der Server neu gestartet wird, damit Rails ActiveRecord
die Zeitstempel im Datensatz verfolgt.
Viele Antworten hier, aber ich werde auch meine posten, weil keine der vorherigen wirklich für mich funktioniert hat :)
Wie einige angemerkt haben, wird #add_timestamps
leider die null: false
Einschränkung hinzugefügt, die dazu führt, dass alte Zeilen ungültig werden, da diese Werte nicht ausgefüllt sind. Die meisten Antworten hier legen nahe, dass wir einen Standardwert ( Time.zone.now
) festlegen , aber ich würde das nicht gerne tun, da diese Standardzeitstempel für alte Daten nicht korrekt sind. Ich sehe den Wert nicht darin, der Tabelle falsche Daten hinzuzufügen.
Meine Migration war also einfach:
class AddTimestampsToUser < ActiveRecord::Migration
def change_table
add_column :projects, :created_at, :datetime
add_column :projects, :updated_at, :datetime
end
end
Nein null: false
, keine weiteren Einschränkungen. Alte Zeilen bleiben mit created_at
as NULL
und update_at
as weiterhin gültig NULL
(bis eine Aktualisierung der Zeile durchgeführt wird). Neue Zeilen haben created_at
und updated_at
wie erwartet bevölkert.
Das Problem mit den meisten Antworten hier ist, dass, wenn Sie standardmäßig Time.zone.now
alle Datensätze verwenden, die Zeit, zu der die Migration ausgeführt wurde, als Standardzeit angegeben wird, was wahrscheinlich nicht das ist, was Sie möchten. In Schienen 5 können Sie stattdessen verwenden now()
. Dadurch werden die Zeitstempel für vorhandene Datensätze als Zeitpunkt der Ausführung der Migration und als Startzeit der Festschreibungstransaktion für neu eingefügte Datensätze festgelegt.
class AddTimestampsToUsers < ActiveRecord::Migration
def change
add_timestamps :users, default: -> { 'now()' }, null: false
end
end
Die Verwendung Time.current
ist ein guter Stil 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
oder
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
Dies ist einfach, um einen Zeitstempel in eine vorhandene Tabelle einzufügen.
class AddTimeStampToCustomFieldMeatadata < ActiveRecord::Migration
def change
add_timestamps :custom_field_metadata
end
end
Für diejenigen, die keine Rails verwenden, aber activerecord verwenden, wird im Folgenden auch eine Spalte zu einem vorhandenen Modell hinzugefügt. Ein Beispiel ist ein ganzzahliges Feld.
ActiveRecord::Schema.define do
change_table 'MYTABLE' do |table|
add_column(:mytable, :my_field_name, :integer)
end
end
Dies scheint eine saubere Lösung in Rails 5.0.7 zu sein (die Methode change_column_null wurde entdeckt):
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
Ich bin auf Rails 5.0 und keine dieser Optionen hat funktioniert.
Das einzige, was funktionierte, war die Verwendung des Typs: Zeitstempel und nicht: Datum / Uhrzeit
def change
add_column :users, :created_at, :timestamp
add_column :users, :updated_at, :timestamp
end
Ich persönlich habe Folgendes verwendet und alle vorherigen Datensätze mit der aktuellen Uhrzeit / dem aktuellen Datum aktualisiert:
add_column :<table>, :created_at, :datetime, default: Time.zone.now, null: false
add_column :<table>, :updated_at, :datetime, default: Time.zone.now, null: false
Ich bin auf Rails 5 auf dasselbe Problem gestoßen, als ich versucht habe, es zu verwenden
change_table :my_table do |t|
t.timestamps
end
Ich konnte die Zeitstempelspalten manuell wie folgt hinzufügen:
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