Respuestas:
El asistente de marca de tiempo solo está disponible en el create_table
bloque. Puede agregar estas columnas especificando los tipos de columna manualmente:
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
Si bien esto no tiene la misma sintaxis concisa que el add_timestamps
método que especificó anteriormente, Rails seguirá tratando estas columnas como columnas de marca de tiempo y actualizará los valores normalmente.
rails g migration AddTimestampsToUser created_at:datetime updated_at:datetime
- un atajo para generar la migración anterior.
PG::NotNullViolation: ERROR: column "created_at" contains null value
porque mi tabla ya contiene datos que violan la restricción no nula. ¿Alguna mejor manera de hacerlo que eliminar la contracción no nula al principio y luego agregarla?
add_column :users, :updated_at, :datetime, null: false, default: Time.zone.now
. Time.zone.now
es solo un ejemplo, debe usar cualquier valor que tenga sentido para su lógica.
Las migraciones son solo dos métodos de clase (o métodos de instancia en 3.1): up
y down
(y a veces un change
método de instancia en 3.1). Desea que sus cambios entren en el up
método:
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
Si está en 3.1, entonces también podría usar change
(gracias Dave):
class AddTimestampsToUser < ActiveRecord::Migration
def change
change_table(:users) { |t| t.timestamps }
end
end
Tal vez estás confundiendo def change
, def change_table
y change_table
.
Consulte la guía de migración para más detalles.
change
ahora está el método, aunque en este caso, no es el problema :)
change
vale la pena mencionarlo, así que también lo agregaré.
Su código original está muy cerca de la derecha, solo necesita usar un nombre de método diferente. Si está utilizando Rails 3.1 o posterior, debe definir un change
método en lugar de change_table
:
class AddTimestampsToUser < ActiveRecord::Migration
def change
add_timestamps(:users)
end
end
Si está utilizando una versión anterior, debe definir métodos up
y down
métodos en lugar de change_table
:
class AddTimestampsToUser < ActiveRecord::Migration
def up
add_timestamps(:users)
end
def down
remove_timestamps(:users)
end
end
La respuesta de @ user1899434 recogió el hecho de que una tabla "existente" aquí podría significar una tabla con registros ya en ella, registros que quizás no desee eliminar. Entonces, cuando agrega marcas de tiempo con nulo: falso, que es el valor predeterminado y, a menudo, deseable, todos los registros existentes no son válidos.
Pero creo que esa respuesta puede mejorarse, combinando los dos pasos en una migración, y usando el método más semántico 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
Podría sustituir alguna otra marca de tiempo DateTime.now
, como si quisiera crear / actualizar registros preexistentes al comienzo de los tiempos.
Time.zone.now
es lo que se debe usar si queremos que nuestro código obedezca a la zona horaria correcta.
Time.zone.now
que devolverá la instancia de Time que se crea cuando se ejecuta la migración y solo usará ese tiempo como predeterminado. Los nuevos objetos no obtendrán una nueva instancia de Time.
class AddTimestampsToUser < ActiveRecord::Migration
def change
change_table :users do |t|
t.timestamps
end
end
end
Las transformaciones disponibles son
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 respuesta de Nick Davies es la más completa en términos de agregar columnas de marca de tiempo a una tabla con datos existentes. Su único inconveniente es que aumentará ActiveRecord::IrreversibleMigration
en a db:rollback
.
Debe modificarse así para trabajar en ambas direcciones:
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
no es compatible from
y to
en esa versión?), ¡Pero tomé esta idea y creé up/down
métodos en lugar de un solo change
método y funcionó de maravilla!
def change
add_timestamps :table_name
end
no estoy seguro de cuándo se introdujo exactamente esto, pero en rails 5.2.1 puede hacer esto:
class AddTimestampsToMyTable < ActiveRecord::Migration[5.2]
def change
add_timestamps :my_table
end
end
para obtener más información, consulte " uso del método de cambio " en los documentos de migraciones de registros activos.
, null: true
después del:my_table
Hice una función simple que puede llamar para agregar a cada tabla (suponiendo que tenga una base de datos existente) los campos created_at y updated_at :
# 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
Agrega columnas de marcas de tiempo (created_at y updated_at) a table_name. Las opciones adicionales (como null: false) se envían a #add_column.
class AddTimestampsToUsers < ActiveRecord::Migration
def change
add_timestamps(:users, null: false)
end
end
Las respuestas anteriores parecen correctas, sin embargo, tuve problemas si mi tabla ya tiene entradas.
Obtendría 'ERROR: la columna created_at
contiene null
valores'.
Para arreglarlo, usé:
def up
add_column :projects, :created_at, :datetime, default: nil, null: false
add_column :projects, :updated_at, :datetime, default: nil, null: false
end
Luego usé la gema migración_datos para agregar el tiempo para los proyectos actuales en la migración, tales como:
def data
Project.update_all created_at: Time.now
end
Luego, todos los proyectos creados después de esta migración se actualizarán correctamente. Asegúrese de que el servidor también se reinicie para que Rails ActiveRecord
comience a rastrear las marcas de tiempo en el registro.
Muchas respuestas aquí, pero también publicaré las mías porque ninguna de las anteriores realmente funcionó para mí :)
Como algunos han notado, #add_timestamps
desafortunadamente agrega la null: false
restricción, lo que hará que las filas antiguas no sean válidas porque no tienen estos valores rellenados. La mayoría de las respuestas aquí sugieren que establezcamos un valor predeterminado (Time.zone.now
), pero no me gustaría hacerlo porque estas marcas de tiempo predeterminadas para datos antiguos no serán correctas. No veo el valor en agregar datos incorrectos a la tabla.
Entonces mi migración fue simplemente:
class AddTimestampsToUser < ActiveRecord::Migration
def change_table
add_column :projects, :created_at, :datetime
add_column :projects, :updated_at, :datetime
end
end
No null: false
, no hay otras restricciones. Las filas antiguas continuarán siendo válidas con created_at
as NULL
y update_at
como NULL
(hasta que se realice alguna actualización en la fila). Las nuevas filas tendrán created_at
y se completarán updated_at
como se esperaba.
El problema con la mayoría de las respuestas aquí es que si usa Time.zone.now
todos los registros de manera predeterminada , el tiempo de ejecución de la migración será el tiempo predeterminado, lo que probablemente no sea lo que desea. En los rieles 5 puedes usarlos now()
. Esto establecerá las marcas de tiempo para los registros existentes como la hora en que se ejecutó la migración y como la hora de inicio de la transacción de confirmación para los registros recién insertados.
class AddTimestampsToUsers < ActiveRecord::Migration
def change
add_timestamps :users, default: -> { 'now()' }, null: false
end
end
Usar Time.current
es un buen estilo 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
Este es uno simple para agregar marca de tiempo en la tabla existente.
class AddTimeStampToCustomFieldMeatadata < ActiveRecord::Migration
def change
add_timestamps :custom_field_metadata
end
end
Esto parece una solución limpia en Rails 5.0.7 (descubrió el método 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
Estoy en rails 5.0 y ninguna de estas opciones funcionó.
Lo único que funcionó fue usar el tipo to be: timestamp y not: datetime
def change
add_column :users, :created_at, :timestamp
add_column :users, :updated_at, :timestamp
end
Me encontré con el mismo problema en Rails 5 tratando de usar
change_table :my_table do |t|
t.timestamps
end
Pude agregar las columnas de marca de tiempo manualmente con lo siguiente:
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