Ruby on Rails | Screencasts | Download | Documentation | Weblog | Community | Source

Ticket #2873 (closed defect: duplicate)

Opened 4 years ago

Last modified 4 years ago

PostgreSQL time field with now() as default gets unchanging value

Reported by: alex@purefiction.net Assigned to: Jeremy Kemper <rails@bitsweat.net>
Priority: high Milestone: 1.1
Component: ActiveRecord Version: 0.14.3
Severity: major Keywords: PostgreSQL time date timestamp default now
Cc:

Description

Given a table such as this:

create table foo
(
  id serial,
  time timestamp default now()
);

The "time" field, if not explicitly assigned by the application, will get a value assigned by PostgreSQLAdapter#default_value -- it returns Time.now.to_s for such columns.

Unfortunately, in production mode this defaults-assignment logic seems to be invoked only once; thus from the application's perspective, all time unassigned fields will get the time at which the Rails processed started.

For many apps this is not a problem, but it *is* a problem if you depend on "created_at" being maintained automatically.

I started thinking I could patch this, but the problem seems pretty deeply rooted in how ActiveRecord handles default values. Column#default, after all, is expected to be a static value, not a function. Thus dynamic column-level defaults (ie., ones that invoke a database-side function) is generally not supported.

In fact, the logic in !PostgreSQLAdapter to support PostgreSQL's now() function is really a special-case kludge. So if I were to fix anything it would be to make PostgreSQLAdapter#default_value return nil for cases where the schema uses a function default. This lets the data flow through ActiveRecord correctly.

Change History

11/15/05 03:29:30 changed by bitsweat

  • owner changed from David to Jeremy Kemper <rails@bitsweat.net>.
  • priority changed from normal to high.
  • severity changed from normal to major.
  • milestone set to 1.1.

This is a known problem covered in some old tickets. Default handling in general needs revisiting.

In the meantime, use callbacks

class Foo < AR::Base
  before_save { |foo| foo.time = Time.now }
end

11/15/05 14:13:02 changed by stephen_purcell@yahoo.com

Having also been bitten very badly by this, I second the original poster's suggestion that PostgreSQLAdapter#default_value return nil for the 'now()'.

I will submit a patch making this change.

-Steve

11/15/05 14:18:25 changed by stephen_purcell@yahoo.com

Patch is #2877

11/15/05 14:54:55 changed by alex@purefiction.net

Thanks.

11/15/05 15:31:57 changed by bitsweat

  • status changed from new to closed.
  • resolution set to duplicate.

Returning nil may be a viable choice for your apps; go for it. But it is a stopgap solution which results in many regressions, so we need a better fix (real default handling.)

Duplicates #2257.