Ответы:
Помощник по временной метке доступен только в create_table
блоке. Вы можете добавить эти столбцы, указав типы столбцов вручную:
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
Хотя это не имеет тот же краткий синтаксис, что и add_timestamps
метод, который вы указали выше, Rails все равно будет обрабатывать эти столбцы как столбцы меток времени и обновлять значения в обычном режиме.
rails g migration AddTimestampsToUser created_at:datetime updated_at:datetime
- ярлык для генерации миграции выше.
PG::NotNullViolation: ERROR: column "created_at" contains null value
потому что моя таблица уже содержит данные, которые нарушают ненулевое ограничение. Есть ли лучший способ сделать это, чем сначала удалить ненулевое ограничение, а потом добавить его?
add_column :users, :updated_at, :datetime, null: false, default: Time.zone.now
. Time.zone.now
Это просто пример, вы должны использовать любое значение, имеющее смысл для вашей логики.
Миграции - это всего лишь два метода класса (или методы экземпляра в 3.1): up
и down
(а иногда и change
метод экземпляра в 3.1). Вы хотите, чтобы ваши изменения вошли в up
метод:
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
Если вы в 3.1, то вы также можете использовать change
(спасибо Дэйв):
class AddTimestampsToUser < ActiveRecord::Migration
def change
change_table(:users) { |t| t.timestamps }
end
end
Возможно , ты путаешь def change
, def change_table
и change_table
.
См. Руководство по миграции для получения дополнительной информации.
change
метод сейчас, хотя в этом случае, не проблема :)
change
стоит упомянуть, поэтому я добавлю это тоже.
Ваш исходный код очень близок к правильному, вам просто нужно использовать другое имя метода. Если вы используете Rails 3.1 или новее, вам нужно определить change
метод вместо change_table
:
class AddTimestampsToUser < ActiveRecord::Migration
def change
add_timestamps(:users)
end
end
Если вы используете более старую версию, вам нужно определить up
и down
методы вместо change_table
:
class AddTimestampsToUser < ActiveRecord::Migration
def up
add_timestamps(:users)
end
def down
remove_timestamps(:users)
end
end
Ответ @ user1899434 был основан на том факте, что «существующая» таблица здесь может означать таблицу с уже имеющимися записями, записи, которые вы, возможно, не хотите удалять. Поэтому, когда вы добавляете временные метки со значением null: false, которое является значением по умолчанию и часто желательно, все существующие записи становятся недействительными.
Но я думаю, что этот ответ можно улучшить, объединив два шага в одну миграцию, а также используя более семантический метод 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
Вы можете заменить некоторую другую временную метку DateTime.now
, например, если вы хотите, чтобы ранее созданные записи создавались / обновлялись на заре времени.
Time.zone.now
это то, что следует использовать, если мы хотим, чтобы наш код соответствовал правильному часовому поясу.
Time.zone.now
которая будет возвращать экземпляр Time, созданный при запуске миграции, и просто использовать это время по умолчанию. Новые объекты не получат новый экземпляр времени.
class AddTimestampsToUser < ActiveRecord::Migration
def change
change_table :users do |t|
t.timestamps
end
end
end
Доступные преобразования
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
Ник Дэвис ответ является наиболее полным с точки зрения добавления столбцов отметок времени в таблицу с существующими данными. Единственным недостатком является то, что он будет повышаться ActiveRecord::IrreversibleMigration
наdb:rollback
.
Это должно быть изменено так, чтобы работать в обоих направлениях:
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
что не поддерживает from
и to
в этой версии?), Но я взял эту идею и создал up/down
методы вместо одного change
метода, и это сработало как шарм!
не уверен, когда именно это было введено, но в rails 5.2.1 вы можете сделать это:
class AddTimestampsToMyTable < ActiveRecord::Migration[5.2]
def change
add_timestamps :my_table
end
end
для получения дополнительной информации см. « Использование метода изменения » в документации по переносу активных записей.
, null: true
после:my_table
Я сделал простую функцию, которую вы можете вызвать, чтобы добавить в каждую таблицу (при условии, что у вас есть существующая база данных) поля create_at и 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
Добавляет столбцы временных меток (созданный и обновленный_кат) в имя_таблицы. Дополнительные параметры (например, null: false) пересылаются в #add_column.
class AddTimestampsToUsers < ActiveRecord::Migration
def change
add_timestamps(:users, null: false)
end
end
Предыдущие ответы кажутся правильными, однако я столкнулся с проблемами, если в моей таблице уже есть записи.
Я бы получил «ОШИБКА: столбец created_at
содержит null
значения».
Чтобы исправить, я использовал:
def up
add_column :projects, :created_at, :datetime, default: nil, null: false
add_column :projects, :updated_at, :datetime, default: nil, null: false
end
Затем я использовал драгоценные migration_data , чтобы добавить время для текущих проектов по миграции , такие как:
def data
Project.update_all created_at: Time.now
end
Тогда все проекты, созданные после этой миграции, будут корректно обновлены. Убедитесь, что сервер тоже перезапущен, чтобы Rails ActiveRecord
начал отслеживать временные метки в записи.
Здесь много ответов, но я также опубликую свой, потому что ни один из предыдущих не помог мне :)
Как уже отмечалось, #add_timestamps
к сожалению, добавляется null: false
ограничение, которое приводит к тому , что старые строки становятся недопустимыми, потому что эти значения не заполнены. Большинство ответов здесь предполагают, что мы установили некоторое значение по умолчанию ( Time.zone.now
), но я бы не хотел этого делать, потому что эти временные метки по умолчанию для старых данных не будут правильными. Я не вижу смысла в добавлении неверных данных в таблицу.
Так что моя миграция была просто:
class AddTimestampsToUser < ActiveRecord::Migration
def change_table
add_column :projects, :created_at, :datetime
add_column :projects, :updated_at, :datetime
end
end
Нет null: false
, других ограничений нет. Старые строки будут продолжать действовать created_at
как as NULL
и update_at
as NULL
(пока не будет выполнено какое-либо обновление строки). Новые строки будут иметь created_at
и updated_at
населен , как и ожидалось.
Проблема с большинством ответов здесь заключается в том, что если вы по умолчанию для Time.zone.now
всех записей будете иметь время запуска миграции в качестве времени по умолчанию, что, вероятно, не то, что вы хотите. В рельсах 5 вы можете использовать вместо этого now()
. Это установит временные метки для существующих записей как время выполнения миграции и как время начала транзакции фиксации для вновь вставленных записей.
class AddTimestampsToUsers < ActiveRecord::Migration
def change
add_timestamps :users, default: -> { 'now()' }, null: false
end
end
Использование Time.current
это хороший стиль 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
или
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
Это простой способ добавить метку времени в существующую таблицу.
class AddTimeStampToCustomFieldMeatadata < ActiveRecord::Migration
def change
add_timestamps :custom_field_metadata
end
end
Это похоже на чистое решение в Rails 5.0.7 (обнаружен метод 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
Я на рельсах 5.0 и ни один из этих вариантов не сработал.
Единственное, что сработало, это использование типа: timestamp, а не: datetime
def change
add_column :users, :created_at, :timestamp
add_column :users, :updated_at, :timestamp
end
Я столкнулся с той же проблемой на Rails 5, пытаясь использовать
change_table :my_table do |t|
t.timestamps
end
Я смог добавить столбцы метки времени вручную с помощью следующего:
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