190

我需要将时间戳 ( created_at& updated_at) 添加到现有表中。我尝试了以下代码,但没有成功。

class AddTimestampsToUser < ActiveRecord::Migration
    def change_table
        add_timestamps(:users)
    end
end
4

21 回答 21

232

时间戳助手仅在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_timestampsRails 仍会将这些列视为时间戳列,并正常更新值。

于 2011-09-25T01:13:54.313 回答
96

迁移只是两个类方法(或 3.1 中的实例方法):updown(有时是change3.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

有关更多详细信息,请参阅迁移指南

于 2011-09-25T01:14:45.913 回答
81

您的原始代码非常接近正确,您只需要使用不同的方法名称。如果您使用的是 Rails 3.1 或更高版本,则需要定义一个change方法而不是change_table

class AddTimestampsToUser < ActiveRecord::Migration
  def change
    add_timestamps(:users)
  end
end

如果您使用的是旧版本,则需要定义updown方法而不是change_table

class AddTimestampsToUser < ActiveRecord::Migration
  def up
    add_timestamps(:users)
  end

  def down
    remove_timestamps(:users)
  end
end
于 2012-09-30T12:00:18.970 回答
80

@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,例如,如果您希望在黎明时创建/更新预先存在的记录。

于 2017-04-21T17:29:27.493 回答
40
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

于 2011-09-25T02:23:49.880 回答
13

就将时间戳列添加到包含现有数据的表而言,尼克戴维斯的回答是最完整的。它唯一的缺点是它会ActiveRecord::IrreversibleMigrationdb: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
于 2018-09-13T18:51:06.463 回答
9
def change
  add_timestamps :table_name
end
于 2017-03-06T17:38:27.153 回答
7

这里大多数答案的问题是,如果您默认Time.zone.now所有记录都将运行迁移的时间作为其默认时间,这可能不是您想要的。在 rails 5 中,您可以改用now(). 这会将现有记录的时间戳设置为迁移运行的时间,以及新插入记录的提交事务的开始时间。

class AddTimestampsToUsers < ActiveRecord::Migration def change add_timestamps :users, default: -> { 'now()' }, null: false end end

于 2020-02-05T21:56:20.573 回答
7

使用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
于 2020-02-27T09:42:15.090 回答
7

我在 Rails 5.0 上,这些选项都不起作用。

唯一有效的是使用类型为 :timestamp 而不是 :datetime

def change
    add_column :users, :created_at, :timestamp
    add_column :users, :updated_at, :timestamp
end
于 2020-06-16T03:57:47.833 回答
5

不确定这是什么时候引入的,但是在 rails 5.2.1 你可以这样做:

class AddTimestampsToMyTable < ActiveRecord::Migration[5.2]
  def change
    add_timestamps :my_table
  end
end

有关更多信息,请参阅活动记录迁移文档中的“使用更改方法”。

于 2018-11-15T16:41:30.363 回答
4

这似乎是 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
于 2020-04-24T19:57:43.250 回答
3

这里有很多答案,但我也会发布我的答案,因为以前的答案都不适合我:)

正如一些人所指出的,#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_atasNULLupdate_atas NULL(直到对该行执行一些更新)。新行将按预期填充created_at并填充。updated_at

于 2019-07-15T16:43:25.250 回答
2

我做了一个简单的函数,你可以调用它来向每个表(假设你有一个现有的数据库)添加created_atupdated_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
于 2012-08-20T21:25:24.567 回答
2

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
于 2018-06-14T13:28:47.483 回答
2

这是在现有表中添加时间戳的简单方法。

class AddTimeStampToCustomFieldMeatadata < ActiveRecord::Migration
  def change
    add_timestamps :custom_field_metadata
  end
end
于 2020-06-09T05:21:40.543 回答
1

之前的答案似乎是正确的,但是如果我的表已经有条目,我会遇到问题。

我会得到“错误:列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开始跟踪记录上的时间戳。

于 2017-01-12T20:13:12.967 回答
0

对于不使用 Rails 但使用 activerecord 的人,下面还为现有模型添加一列,例如整数字段。

ActiveRecord::Schema.define do
  change_table 'MYTABLE' do |table|
    add_column(:mytable, :my_field_name, :integer)
  end
end
于 2016-12-06T15:00:31.967 回答
0

它是change,不适change_table用于 Rails 4.2:

class AddTimestampsToUsers < ActiveRecord::Migration
  def change
    add_timestamps(:users)
  end
end
于 2018-03-04T11:05:02.340 回答
-1

我个人使用了以下内容,它用当前时间/日期更新了所有以前的记录:

add_column :<table>, :created_at, :datetime, default: Time.zone.now, null: false
add_column :<table>, :updated_at, :datetime, default: Time.zone.now, null: false
于 2017-08-02T14:13:26.843 回答
-1

我在尝试使用 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
于 2019-09-09T17:27:51.750 回答