【问题标题】:Rails fails creating migration with NOW() default value to PostgresRails 无法使用 NOW() 默认值创建迁移到 Postgres
【发布时间】:2013-06-08 14:44:01
【问题描述】:

我常用的方法是

psql > ALTER TABLE transactions ALTER COLUMN date SET DEFAULT CURRENT_TIMESTAMP\g

效果很好。

在我的 RoR 应用中,我尝试以两种方式创建迁移。

1.

class TransactionsSetDefaultDateChange < ActiveRecord::Migration
  change_column :transactions, :date, :datetime, :null=>false, :default=>'CURRENT_TIMESTAMP'
end

2.

class TransactionsSetDefaultDateChange < ActiveRecord::Migration
 execute <<-SQL
    ALTER TABLE transactions ALTER COLUMN date SET DEFAULT CURRENT_TIMESTAMP
 SQL
end

两者都失败了。任何想法为什么?

PS 这种情况适用于迁移(“rake db:migrate”),但未正确应用于“rake db:setup”(丢失 SQL 语句)

class TransactionsSetDefaultDateChange < ActiveRecord::Migration
 def change
 execute <<-SQL
    ALTER TABLE transactions ALTER COLUMN date SET DEFAULT CURRENT_TIMESTAMP
 SQL
 end
end

【问题讨论】:

标签: ruby-on-rails postgresql timestamp migration


【解决方案1】:

对于 Rails 5+,现在可以使用了

... null: false, default: -> { 'NOW()' } ...

在 Postgresql 修饰符中产生类似的东西

not null default now()

【讨论】:

  • 请注意,“截至 10/15”是指 Rails 5 及更高版本。 Rails 4 中不存在此功能。请参阅:github.com/rails/rails/pull/20005
  • 当我尝试这个时,仍然使用 nil 字段创建记录,知道为什么吗? add_column :works, :start_date, :datetime, default: -&gt; { 'NOW()' }
【解决方案2】:

你的问题和答案让我继续前进。对于 Rails 4.2.4 和 Postgres 9.3,以下迁移代码对我有用:

    create_table :goodies do |t|
      t.datetime :last_read_at, null: false
    end
    execute "ALTER TABLE goodies ALTER COLUMN last_read_at SET DEFAULT CURRENT_TIMESTAMP"

它产生了一段工作 SQL:

    last_read_at timestamp without time zone NOT NULL DEFAULT now(),

【讨论】:

    【解决方案3】:

    当然,我们可以在 postgres 中做到这一点。查看我使用 current_timestamp 的示例。它使用“default NOW()”创建列。奇怪的是 rails AR 不支持这样的核心功能。但这不是重点。解决方案是这样修复模型

    before_create :record_date 
    protected 
    def record_date 
        self.date = read_attribute(:date) || Time.now 
    end 
    

    那么,谢谢!

    【讨论】:

      【解决方案4】:

      实现此目的的正确/干净/整洁的方法是使用此迁移:

      class TransactionsSetDefaultDateChange < ActiveRecord::Migration
        change_column :transactions, :date, :datetime, :null=>false, :default=>'now()'
      end
      

      因此,你有:

      • 标准迁移,没有引发 IrreversibleMigration 的特定 sql 命令。
      • 使用时区设置当前时间戳的标准 postgresql 方法
      • 在应用程序级别不需要触发器/过滤器:查看 Transaction.new.date 的输出
      • 可与 mysql 等其他 RDBMS 配合使用

      【讨论】:

      • 实际上,我发现当您执行此操作并检查数据库中的约束时, now() 已被评估,并且默认值最终是其创建时的值,如果这是行为,那么您的答案是错误的。如果需要备份,我可以稍后提供更多信息。
      • Dean 是对的,这不适用于 Rails 4.1 和 PG 0.17.1。创建的列将默认为迁移运行的时间,而不是该行的创建时间。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-05-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-09-04
      • 1970-01-01
      相关资源
      最近更新 更多