将时间戳添加到现有表

时间:2011-09-25 01:05:25

标签: ruby-on-rails ruby rails-activerecord rails-migrations

我需要将时间戳(created_at updated_at)添加到现有表中。我尝试了以下代码,但它没有用。我也尝试过我在网上找到的其他解决方案,但它们也不起作用。

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

我该怎么做?

21 个答案:

答案 0 :(得分:193)

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

答案 1 :(得分:85)

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

如果您在3.1中,那么您也可以使用change(感谢Dave):

class AddTimestampsToUser < ActiveRecord::Migration
  def change
    change_table(:users) { |t| t.timestamps }
  end
end

也许您会混淆def changedef change_tablechange_table

有关详细信息,请参阅migration guide

答案 2 :(得分:70)

您的原始代码非常接近,您只需要使用不同的方法名称。如果您使用的是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

答案 3 :(得分:39)

@ 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的其他时间戳,就像您希望在黎明时刻创建/更新预先存在的记录一样。

答案 4 :(得分:37)

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

答案 5 :(得分:8)

def change
  add_timestamps :table_name
end

答案 6 :(得分:5)

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

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

答案 7 :(得分:4)

就将时间戳列添加到具有现有数据的表而言,

Nick Davies answer是最完整的。它唯一的缺点是它将在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

答案 8 :(得分:3)

使用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

答案 9 :(得分:2)

我做了一个简单的功能,您可以调用添加到每个表(假设您有一个现有的数据库) 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

答案 10 :(得分:2)

  

add_timestamps(table_name,options = {})public

将时间戳(created_at和updated_at)列添加到table_name。其他选项(如null:false)将转发到#add_column。

class AddTimestampsToUsers < ActiveRecord::Migration
  def change
    add_timestamps(:users, null: false)
  end
end

答案 11 :(得分:2)

不确定何时确切引入此方法,但是在rails 5.2.1中可以执行以下操作:

@media screen and (max-width: 768px) {
  .m-re{
    display:none
  }
}

有关更多信息,请参见活动记录迁移文档中的“ using the change method”。

答案 12 :(得分:1)

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

我会得到错误:列created_at包含null值&#39;。

要修复,我用过:

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开始跟踪记录上的时间戳。

答案 13 :(得分:1)

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

class AddTimeStampToCustomFieldMeatadata < ActiveRecord::Migration
  def change
    add_timestamps :custom_field_metadata
  end
end

答案 14 :(得分:1)

这似乎是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

答案 15 :(得分:0)

我正在使用Rails 5.0,但这些选项均无效。

唯一起作用的是使用类型为:timestamp而不是:datetime

def change
    add_column :users, :created_at, :timestamp
    add_column :users, :updated_at, :timestamp
end

答案 16 :(得分:0)

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

有些人指出,#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_atNULLupdate_atNULL(直到对该行执行了一些更新)。新行将按预期填充created_atupdated_at

答案 17 :(得分:0)

它是change,而不是change_table对于Rails 4.2:

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

答案 18 :(得分:0)

对于那些不使用Rails但使用activerecord的人,以下内容还会向现有模型添加一列,例如整数字段。

.

答案 19 :(得分:-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

答案 20 :(得分:-2)

我在尝试使用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