Respuestas:
El asistente de marca de tiempo solo está disponible en el create_tablebloque. 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_timestampsmé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.nowes 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): upy down(y a veces un changemétodo de instancia en 3.1). Desea que sus cambios entren en el upmé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_tabley change_table.
Consulte la guía de migración para más detalles.
changeahora está el método, aunque en este caso, no es el problema :)
changevale 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 changemé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 upy downmé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.nowes lo que se debe usar si queremos que nuestro código obedezca a la zona horaria correcta.
Time.zone.nowque 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::IrreversibleMigrationen 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_defaultno es compatible fromy toen esa versión?), ¡Pero tomé esta idea y creé up/downmétodos en lugar de un solo changemé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: truedespué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_atcontiene nullvalores'.
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 ActiveRecordcomience 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_timestampsdesafortunadamente agrega la null: falserestricció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_atas NULLy update_atcomo NULL(hasta que se realice alguna actualización en la fila). Las nuevas filas tendrán created_aty se completarán updated_atcomo se esperaba.
El problema con la mayoría de las respuestas aquí es que si usa Time.zone.nowtodos 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.currentes 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