如何设置datetime列的默认值以记录迁移中的创建时间?

时间:2009-10-16 22:54:33

标签: ruby-on-rails

考虑下面的表创建脚本:

create_table :foo do |t|
  t.datetime :starts_at, :null => false
end

是否可以将默认值设置为当前时间?

我试图在rails中为下面给出的SQL列定义找到数据库独立的等价物:

Oracle语法

start_at DATE DEFAULT SYSDATE() 

MySQL语法

start_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP

OR

start_at DATETIME DEFAULT NOW()

8 个答案:

答案 0 :(得分:140)

现在Rails 5支持这一点。

以下是迁移示例:

class CreatePosts < ActiveRecord::Migration[5.0]
  def change
    create_table :posts do |t|
      t.datetime :modified_at, default: -> { 'CURRENT_TIMESTAMP' }
      t.timestamps
    end
  end 
end

https://github.com/rails/rails/issues/27077的讨论,然后通过prathamesh-sonpatki回答

答案 1 :(得分:114)

您可以在这样的模型中添加一个函数:

  before_create :set_foo_to_now
  def set_foo_to_now
    self.foo = Time.now
  end

这样模型就会在模型中设置当前时间。

您还可以在迁移中放置一些sql代码,以便在数据库级别设置默认值,如:

execute 'alter table foo alter column starts_at set default now()'

设置如下内容:

create_table :foo do |t|
  t.datetime :starts_at, :null => false, :default => Time.now
end

导致在迁移期间执行Time.now函数,因此数据库中的表创建如下:

create table foo ( starts_at timestamp not null default '2009-01-01 00:00:00');

但我认为这不是你想要的。

答案 2 :(得分:12)

  如果表具有名为created_at / created_onupdated_at / updated_on的字段,则

Active Record会自动为时间戳创建和更新操作。 Source - api.rubyonrails.org

除了拥有该列之外,您不需要做任何其他事情。

答案 3 :(得分:9)

我正在寻找类似的解决方案但我最后使用https://github.com/FooBarWidget/default_value_for

default_value_for插件允许以声明方式定义ActiveRecord模型的默认值。例如:

class User < ActiveRecord::Base
  default_value_for :name, "(no name)"
  default_value_for :last_seen do
    Time.now
  end
end

u = User.new
u.name       # => "(no name)"
u.last_seen  # => Mon Sep 22 17:28:38 +0200 2008

答案 4 :(得分:9)

我通常会这样做:

def change
  execute("
    ALTER TABLE your_table
    ALTER COLUMN your_column
    SET DEFAULT CURRENT_TIMESTAMP
  ")
end

所以,你的schema.rb会有类似的东西:

create_table "your_table", force: :cascade do |t|
  t.datetime "your_column", default: "now()"
end

答案 5 :(得分:5)

如果您需要在Rails 5中更改 现有DateTime列(而不是按照其他答案中的指定创建新表),以便它可以利用默认日期功能,您可以创建这样的迁移:

class MakeStartsAtDefaultDateForFoo < ActiveRecord::Migration[5.0]
  def change
    change_column :foos, :starts_at, :datetime, default: -> { 'CURRENT_TIMESTAMP' }
  end
end

答案 6 :(得分:0)

你知道upserts fail unless you have a default updated_at/created_at吗????

没有自动执行此操作的迁移标志,您必须手动包含带有 default 键的选项对象

create_table :table_foos do |t|
  #...
  # date with timestamp
  t.datetime :last_something_at, null: false, default: -> { "CURRENT_TIMESTAMP" }
  
  # standard timestamps
  t.timestamps({default: -> { "CURRENT_TIMESTAMP" }})
end

答案 7 :(得分:-1)

在@ szymon-lipiński(SzymonLipiński)给出的答案中,执行方法对我不起作用。它抛出了MySQL语法错误。

对我有用的MySQL语法是这样的。

execute "ALTER TABLE mytable CHANGE `column_name` `column_name` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP"

因此,要在迁移脚本中设置日期时间列的默认值,请按以下步骤操作:

def up
  create_table :foo do |t|
    t.datetime :starts_at, :null => false
  end

  execute "ALTER TABLE `foo` CHANGE `starts_at` `starts_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP"
end