Answers:
时间戳帮助器仅在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仍会将这些列视为timestamp列,并正常更新值。
rails g migration AddTimestampsToUser created_at:datetime updated_at:datetime
-生成上述迁移的快捷方式。
PG::NotNullViolation: ERROR: column "created_at" contains null value
因为我的表已包含违反非null约束的数据。有什么比首先删除not null约束然后再添加它更好的方法呢?
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
(感谢Dave):
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实例,并且仅将该时间用作默认值。新对象将不会获得新的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
就将时间戳列添加到具有现有数据的表而言,Nick Davies的答案是最完整的。它唯一的缺点是,它会提高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
方法和它的工作就像一个魅力!
def change
add_timestamps :table_name
end
不知道是什么时候引入的,但是在rails 5.2.1中可以执行以下操作:
class AddTimestampsToMyTable < ActiveRecord::Migration[5.2]
def change
add_timestamps :my_table
end
end
有关更多信息,请参见活动记录迁移文档中的“ 使用更改方法 ”。
, null: true
后:my_table
之前的答案似乎是正确的,但是如果我的表已经有条目,我就会遇到问题。
我会收到“错误:列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
然后,将正确更新此迁移后创建的所有项目。确保服务器也重新启动,以便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.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上,这些选项都不起作用。
唯一起作用的是使用类型为: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