Respostas:
O auxiliar de carimbo de data / hora está disponível apenas no create_table
bloco. Você pode adicionar essas colunas especificando os tipos de coluna 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
Embora isso não tenha a mesma sintaxe concisa que o add_timestamps
método especificado acima, o Rails ainda tratará essas colunas como colunas de carimbo de data e hora e atualizará os valores normalmente.
rails g migration AddTimestampsToUser created_at:datetime updated_at:datetime
- um atalho para gerar a migração acima.
PG::NotNullViolation: ERROR: column "created_at" contains null value
porque minha tabela já contém dados que violam restrições não nulas. Existe uma maneira melhor de fazer isso do que remover primeiro a contraint não nula e depois adicioná-la mais tarde?
add_column :users, :updated_at, :datetime, null: false, default: Time.zone.now
. Time.zone.now
é apenas um exemplo, você deve usar qualquer valor que faça sentido para sua lógica.
As migrações são apenas dois métodos de classe (ou métodos de instância na 3.1): up
e down
(e às vezes um change
método de instância na 3.1). Você deseja que suas alterações entrem no 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
Se você estiver na versão 3.1, também poderá usar change
(obrigado Dave):
class AddTimestampsToUser < ActiveRecord::Migration
def change
change_table(:users) { |t| t.timestamps }
end
end
Talvez você está confuso def change
, def change_table
e change_table
.
Consulte o guia de migração para obter mais detalhes.
change
método agora, embora, neste caso, não é a questão :)
change
vale a pena mencionar, então eu vou adicionar isso também.
Seu código original está muito próximo da direita, você só precisa usar um nome de método diferente. Se você estiver usando o Rails 3.1 ou posterior, precisará definir um change
método em vez de change_table
:
class AddTimestampsToUser < ActiveRecord::Migration
def change
add_timestamps(:users)
end
end
Se você estiver usando uma versão mais antiga, precisará definir up
e down
métodos em vez de change_table
:
class AddTimestampsToUser < ActiveRecord::Migration
def up
add_timestamps(:users)
end
def down
remove_timestamps(:users)
end
end
A resposta de @ user1899434 se deu conta de que uma tabela "existente" aqui poderia significar uma tabela com registros já nela, registros que talvez você não queira descartar. Portanto, quando você adiciona carimbos de data / hora com null: false, que é o padrão e geralmente desejável, esses registros existentes são todos inválidos.
Mas acho que essa resposta pode ser melhorada, combinando as duas etapas em uma migração e usando o método add_timestamps mais semântico:
def change
add_timestamps :projects, default: Time.zone.now
change_column_default :projects, :created_at, nil
change_column_default :projects, :updated_at, nil
end
Você pode substituir outro carimbo de data / hora DateTime.now
, como se desejasse que os registros preexistentes fossem criados / atualizados logo no início.
Time.zone.now
é o que deve ser usado se quisermos que nosso código obedeça ao fuso horário correto.
Time.zone.now
que retornará a instância Time criada quando a migração for executada e usará esse horário como padrão. Novos objetos não receberão uma nova instância de Time.
class AddTimestampsToUser < ActiveRecord::Migration
def change
change_table :users do |t|
t.timestamps
end
end
end
As transformações disponíveis são
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
A resposta de Nick Davies é a mais completa em termos de adição de colunas de carimbo de data / hora a uma tabela com dados existentes. Sua única desvantagem é que ele vai aumentar ActiveRecord::IrreversibleMigration
em umdb:rollback
.
Deve ser modificado da seguinte maneira para funcionar nas duas direções:
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
que não suporta from
e to
nessa versão?), Mas peguei essa ideia e criei up/down
métodos em vez de um único change
método e funcionou como um encanto!
def change
add_timestamps :table_name
end
Não tenho certeza de quando exatamente isso foi introduzido, mas no Rails 5.2.1 você pode fazer isso:
class AddTimestampsToMyTable < ActiveRecord::Migration[5.2]
def change
add_timestamps :my_table
end
end
para obter mais informações, consulte " usando o método de alteração " nos documentos de migração de registros ativos.
, null: true
after the:my_table
Eu criei uma função simples que você pode chamar para adicionar a cada tabela (supondo que você tenha um banco de dados existente) os campos created_at e 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
Adiciona colunas de registro de data e hora (created_at e updated_at) ao nome_tabela. Opções adicionais (como null: false) são encaminhadas para #add_column.
class AddTimestampsToUsers < ActiveRecord::Migration
def change
add_timestamps(:users, null: false)
end
end
As respostas anteriores parecem corretas, no entanto, eu enfrentei problemas se minha tabela já tiver entradas.
Eu receberia 'ERRO: a coluna created_at
contém null
valores'.
Para consertar, eu usei:
def up
add_column :projects, :created_at, :datetime, default: nil, null: false
add_column :projects, :updated_at, :datetime, default: nil, null: false
end
Em seguida, usei o gem migration_data para adicionar o tempo para projetos atuais na migração, como:
def data
Project.update_all created_at: Time.now
end
Todos os projetos criados após essa migração serão atualizados corretamente. Verifique se o servidor também foi reiniciado para que o Rails ActiveRecord
comece a rastrear os carimbos de data e hora no registro.
Muitas respostas aqui, mas vou postar as minhas também porque nenhuma das anteriores realmente funcionou para mim :)
Como alguns observaram, #add_timestamps
infelizmente , adiciona a null: false
restrição, o que fará com que as linhas antigas sejam inválidas porque elas não têm esses valores preenchidos. A maioria das respostas aqui sugere que definimos algum valor padrão (Time.zone.now
), mas eu não gostaria de fazer isso porque esses carimbos de data e hora padrão para dados antigos não estarão corretos. Não vejo o valor em adicionar dados incorretos à tabela.
Então, minha migração foi simplesmente:
class AddTimestampsToUser < ActiveRecord::Migration
def change_table
add_column :projects, :created_at, :datetime
add_column :projects, :updated_at, :datetime
end
end
Não null: false
, não há outras restrições. As linhas antigas continuarão sendo válidas com created_at
as NULL
e update_at
as NULL
(até que alguma atualização seja realizada na linha). Novas linhas terão created_at
e serão updated_at
preenchidas conforme o esperado.
O problema com a maioria das respostas aqui é que, se você usar como padrão Time.zone.now
todos os registros, terá o tempo em que a migração foi executada como o tempo padrão, o que provavelmente não é o que você deseja. Nos trilhos 5, você pode usar now()
. Isso definirá os registros de data e hora dos registros existentes como a hora em que a migração foi executada e como a hora de início da transação de confirmação dos registros inseridos recentemente.
class AddTimestampsToUsers < ActiveRecord::Migration
def change
add_timestamps :users, default: -> { 'now()' }, null: false
end
end
Usar Time.current
é um bom 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
ou
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
É simples adicionar um registro de data e hora na tabela existente.
class AddTimeStampToCustomFieldMeatadata < ActiveRecord::Migration
def change
add_timestamps :custom_field_metadata
end
end
Parece uma solução limpa no Rails 5.0.7 (descoberto o 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
Estou nos trilhos 5.0 e nenhuma dessas opções funcionou.
A única coisa que funcionou foi usar o tipo a ser: timestamp e não: datetime
def change
add_column :users, :created_at, :timestamp
add_column :users, :updated_at, :timestamp
end
Corri para o mesmo problema no Rails 5 tentando usar
change_table :my_table do |t|
t.timestamps
end
Consegui adicionar as colunas de carimbo de data / hora manualmente com o seguinte:
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