我需要在一个已有的表中加入时间戳(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
(在 3.1 版本中有时还会有一个 change
实例方法)。您希望将更改放入 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
change
(感谢Dave):class AddTimestampsToUser < ActiveRecord::Migration
def change
change_table(:users) { |t| t.timestamps }
end
end
def change
、def change_table
和change_table
。请参考迁移指南了解更多细节。change
方法了,虽然在这种情况下不是问题 :) - Dave Newtonchange
也值得一提,所以我会加上它。 - mu is too short@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
。 - John GallagherTime.zone.now
存在问题,因为它会返回在运行迁移时创建的时间实例,并将该时间作为默认值。新对象不会获得新的时间实例。 - Tovi Newman你的原始代码非常接近正确,你只需要使用不同的方法名称。如果你正在使用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
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答案在为已有数据的表添加时间戳列方面是最完整的。唯一的缺点是它会在db:rollback
上引发ActiveRecord::IrreversibleMigration
。
应该按照以下方式进行修改,以在两个方向上都能工作:
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
方法,结果非常完美! - Gar使用 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
Time.zone.now
,则所有记录的默认时间将是运行迁移时的时间,这可能不是您想要的。在rails 5中,您可以改用now()
。这将设置现有记录的时间戳为运行迁移的时间,并将新插入记录的开始时间作为提交事务的开始时间。def change
add_timestamps :table_name
end
PG::NotNullViolation: ERROR: column "created_at" contains null values
- MIA我正在使用 Rails 5.0,但这些选项都没有生效。
唯一有效的方法是将类型设置为 :timestamp 而不是 :datetime
def change
add_column :users, :created_at, :timestamp
add_column :users, :updated_at, :timestamp
end
rails g migration AddTimestampsToUser created_at:datetime updated_at:datetime
是生成上述数据库迁移的快捷方式。 - Konstantine KalbazovPG::NotNullViolation: ERROR: column "created_at" contains null value
,这是因为我的表已经包含了违反非空约束的数据。除了先删除非空约束再重新添加之外,是否有更好的方法来解决这个问题? - M. Habibadd_column :users, :updated_at, :datetime, null: false, default: Time.zone.now
。Time.zone.now
只是一个示例,您应该使用适合您逻辑的任何值。 - Delong Gaodef change change_table :users do |t| t.timestamps end end
- Syph