Phil Mok
Phil Mok

Reputation: 4050

Rails set default DateTime to now

In my app I have teams and each team has a game time every week. I want the game times to be set to 'now' as a default. My table is set up like so

create_table "teams", force: true do |t|
  t.datetime "wk1_time"
end

I created a migration and it looks like this:

class ChangeDateTimeDefault < ActiveRecord::Migration
  def change
    change_column :teams, :wk1_time, :default => DateTime.now
  end
end

When I run rake db:migrate I get an error. Is my syntax wrong or am I missing something else?

Upvotes: 14

Views: 22035

Answers (7)

zhisme
zhisme

Reputation: 2800

in rails 7 you should do the following (in case you want your timestamp to be evaluated each time when the row is being inserted)

db/migrate/20240215142705_alter_table_teams.rb

add_column :teams, :wk1_time, :timestamp, null: false, default: -> { "now()" }

which results the follwing structure

wk1_time timestamp without time zone DEFAULT now() NOT NULL

Upvotes: 0

Erik Stoupignan
Erik Stoupignan

Reputation: 7

This works for me:

class MigrationName < ActiveRecord::Migration[7.0]
  def change
    add_column :table_name, :column_name, :integer, default: 100, null: false
    add_column :table_name, :column_name_date_to_save, :datetime, default: DateTime.now
  end
end

Upvotes: -1

oma
oma

Reputation: 40770

EDIT: For Rails 5+ there are better answers, like this one: https://stackoverflow.com/a/55357711/252799, though the below still works.

The way I found, was to do a migration on an existing datetime column, like this:

#migration
execute("ALTER TABLE teams ALTER COLUMN wk1_time SET DEFAULT CURRENT_TIMESTAMP")

that produces a schema.rb entry shown like this:

#schema.rb
t.datetime "wk1_time",                    default: "now()", null: false

The "now()" is a string sent to postgresql and evaluated at runtime, upon each insert.

Upvotes: 8

alexandre-rousseau
alexandre-rousseau

Reputation: 2820

Since Rails 5 you can make a migration like this:

change_column_default :users, :wk1_time, -> { 'CURRENT_TIMESTAMP' }

In my mind this is the best option because it not database specific answer.

Upvotes: 24

Nicolas Maloeuvre
Nicolas Maloeuvre

Reputation: 3169

for Postgresql :

add_column :users, :msgs_seen_at, 'TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP'

but you'll have to use user.reload after user = User.create in order to "see" msgs_seen_at

Upvotes: 1

Arup Rakshit
Arup Rakshit

Reputation: 118261

Yes, you are missing the type :

class ChangeDateTimeDefault < ActiveRecord::Migration
  def change
    change_column :teams, :wk1_time, :datetime, :default => DateTime.now
  end
end

But, you need the below not the above one, because you just want to change the default.

class ChangeDateTimeDefault < ActiveRecord::Migration
  def change
    change_column_default :teams, :wk1_time, DateTime.now
  end
end

But none of these are correct approach for your task. The reason is DateTime.now will be evaluated based upon when you ran the migration, instead when the record is created. You need look to into this answer to know how to set the default time.

Upvotes: 13

Gavin Miller
Gavin Miller

Reputation: 43815

You're going to run into problems settings the default date time in the migration. This is because DateTime.now will be evaluated based upon when the migrate runs, not when the record is created!

To fix that you'll need to create an ActiveRecord callback in order to set wk1_time like so:

before_create :set_default_wk1_datetime
def set_default_wk1_datetime
  self.wk1_time = DateTime.now
end

Upvotes: 4

Related Questions