简体   繁体   中英

Rails fails creating migration with NOW() default value to Postgres

Common way I use it is

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

it works fine.

In my RoR app I've tried to create migrations in two ways.

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

Both failed. Any ideas why?

PS this case works with migration ("rake db:migrate") but is not applied correctly on "rake db:setup" (loses SQL statement)

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

For Rails 5+ this works now

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

Produces something like this in Postgresql Modifiers

not null default now()

Your question and answers here got me going. With Rails 4.2.4 and Postgres 9.3, the following migration code worked for me:

    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"

It produced a piece of working SQL:

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

Of course we can do it in postgres. Check out my example with current_timestamp. It creates column with "default NOW()". Strange that rails AR does not support such a core feature. But it's not the point. The solution is to fix model this way

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

So, thank you!

a correct/clean/neat way to achieve this is with this migration:

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

Therefore, you have:

  • a standard migration, no specific sql commands which raise IrreversibleMigration.
  • the standard postgresql way of setting current timestamps with timezone
  • no need for triggers/filters at application level: Look at the output of Transaction.new.date
  • works with other RDBMS like mysql

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM