我需要将时间戳 ( created_at
& updated_at
) 添加到现有表中。我尝试了以下代码,但没有成功。
class AddTimestampsToUser < ActiveRecord::Migration
def change_table
add_timestamps(:users)
end
end
我需要将时间戳 ( created_at
& updated_at
) 添加到现有表中。我尝试了以下代码,但没有成功。
class AddTimestampsToUser < ActiveRecord::Migration
def change_table
add_timestamps(:users)
end
end
时间戳助手仅在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 仍会将这些列视为时间戳列,并正常更新值。
迁移只是两个类方法(或 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
(感谢 Dave):
class AddTimestampsToUser < ActiveRecord::Migration
def change
change_table(:users) { |t| t.timestamps }
end
end
也许您对def change
,def change_table
和感到困惑change_table
。
有关更多详细信息,请参阅迁移指南。
您的原始代码非常接近正确,您只需要使用不同的方法名称。如果您使用的是 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
,例如,如果您希望在黎明时创建/更新预先存在的记录。
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
def change
add_timestamps :table_name
end
这里大多数答案的问题是,如果您默认Time.zone.now
所有记录都将运行迁移的时间作为其默认时间,这可能不是您想要的。在 rails 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
我在 Rails 5.0 上,这些选项都不起作用。
唯一有效的是使用类型为 :timestamp 而不是 :datetime
def change
add_column :users, :created_at, :timestamp
add_column :users, :updated_at, :timestamp
end
不确定这是什么时候引入的,但是在 rails 5.2.1 你可以这样做:
class AddTimestampsToMyTable < ActiveRecord::Migration[5.2]
def change
add_timestamps :my_table
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
这里有很多答案,但我也会发布我的答案,因为以前的答案都不适合我:)
正如一些人所指出的,#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
asNULL
和update_at
as NULL
(直到对该行执行一些更新)。新行将按预期填充created_at
并填充。updated_at
我做了一个简单的函数,你可以调用它来向每个表(假设你有一个现有的数据库)添加created_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 = {}) 公共
将时间戳(created_at 和 updated_at)列添加到 table_name。附加选项(如 null: false)被转发到#add_column。
class AddTimestampsToUsers < ActiveRecord::Migration
def change
add_timestamps(:users, null: false)
end
end
这是在现有表中添加时间戳的简单方法。
class AddTimeStampToCustomFieldMeatadata < ActiveRecord::Migration
def change
add_timestamps :custom_field_metadata
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
然后,我使用 gem migration_data为迁移中的当前项目添加时间,例如:
def data
Project.update_all created_at: Time.now
end
然后将正确更新此迁移后创建的所有项目。确保服务器也重新启动,以便 RailsActiveRecord
开始跟踪记录上的时间戳。
对于不使用 Rails 但使用 activerecord 的人,下面还为现有模型添加一列,例如整数字段。
ActiveRecord::Schema.define do
change_table 'MYTABLE' do |table|
add_column(:mytable, :my_field_name, :integer)
end
end
它是change
,不适change_table
用于 Rails 4.2:
class AddTimestampsToUsers < ActiveRecord::Migration
def change
add_timestamps(:users)
end
end
我个人使用了以下内容,它用当前时间/日期更新了所有以前的记录:
add_column :<table>, :created_at, :datetime, default: Time.zone.now, null: false
add_column :<table>, :updated_at, :datetime, default: Time.zone.now, null: false
我在尝试使用 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