PostgreSQL9.4下Rails迁移如何将列默认值设为NOW()而非迁移执行时间?
解决Rails迁移中PostgreSQL动态默认时间的问题
我明白你遇到的困扰了——本来想让created_at列在每条记录创建时自动取当前时间,结果迁移跑完后,默认值变成了迁移执行那一刻的固定时间,完全不是预期的动态效果!
问题出在哪?
你原来的代码里传的是字符串'NOW',Rails会把它当成静态值处理:在迁移运行时,它会立即计算NOW对应的时间,然后把这个固定的时间戳设为列的默认值,而不是告诉数据库“每次插入时都执行NOW()函数”。
正确的做法
要让PostgreSQL在每次插入记录时动态计算当前时间,你需要让Rails把NOW()作为SQL表达式传递给数据库,而不是静态值。这里有两种常用的靠谱方式:
方法1:使用Lambda表达式(推荐)
在change_column_default中用lambda包裹SQL表达式,Rails就会识别出这是要交给数据库执行的动态语句:
class ChangeDefaultValueForStratumWorkerSubmissions < ActiveRecord::Migration[5.1] def change change_column_default(:stratum_worker_submissions, :created_at, -> { 'NOW()' }) end end
方法2:直接执行原生SQL
如果你更习惯写原生SQL,也可以用execute方法直接执行ALTER TABLE语句,效果完全一样:
class ChangeDefaultValueForStratumWorkerSubmissions < ActiveRecord::Migration[5.1] def change execute <<-SQL ALTER TABLE stratum_worker_submissions ALTER COLUMN created_at SET DEFAULT NOW(); SQL end end
额外小提醒
其实Rails默认会在创建记录时自动为created_at和updated_at赋值,但如果你的场景需要数据库层面也保证默认值(比如有直接通过SQL插入数据的情况),上面的方法就特别有用啦。
内容的提问来源于stack exchange,提问作者satish
相关产品推荐
相关产品推荐

