Active Record nil timestamp

Viewed 263

I have a table created like shown below.

CREATE TABLE foo(
  id INT PRIMARY KEY AUTO_INCREMENT,
  num INT,
  created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
  updated_at TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
);

After I insert and edit a few values I get the table below.

+----+------+---------------------+---------------------+
| id | num  | created_at          | updated_at          |
+----+------+---------------------+---------------------+
|  1 |   15 | 2020-06-22 11:19:56 | 2020-06-22 11:20:20 |
|  2 |   13 | 2020-06-22 11:19:58 | 0000-00-00 00:00:00 |
|  3 |   14 | 2020-06-22 11:20:01 | 0000-00-00 00:00:00 |
+----+------+---------------------+---------------------+

Then I have the class:

require 'active_record'

class Foo < ActiveRecord::Base
  self.table_name = 'foo'
end
1 Foo.all # => [#<Foo:0x000056314a734188 id: 1, num: 15, created_at: 2020-06-22 11:23:40 UTC, updated_at: 2020-06-22 11:23:48 UTC>, #<Foo:0x000056314a7340c0 id: 2, num: 13, created_at: 2020-06-22 11:23:43 UTC, updated_at: nil>, #<Foo:0x000056314a743f98 id: 3, num: 14, created_at: 2020-06-22 11:23:46 UTC, updated_at: nil>]

2 Foo.where(updated_at: nil) # => []

3 Foo.where.not(updated_at: nil) # => [#<Foo:0x000055aafe3ba6d8 id: 1, num: 15, created_at: 2020-06-22 11:23:40 UTC>, #<Foo:0x000055aafe3ba5e8 id: 2, num: 13, created_at: 2020-06-22 11:23:43 UTC>, #<Foo:0x000055aafe3ba520 id: 3, num: 14, created_at: 2020-06-22 11:23:46 UTC>]

4 Foo.where(updated_at: '0000-00-00 00:00:00') # => []

5 Foo.where.not(updated_at: '0000-00-00 00:00:00') # => []

6 Foo.where("updated_at = '0000-00-00 00:00:00'") # => [#<Foo:0x000056314a8857d0 id: 2, num: 13, created_at: 2020-06-22 11:23:43 UTC, updated_at: nil>, #<Foo:0x000056314a885708 id: 3, num: 14, created_at: 2020-06-22 11:23:46 UTC, updated_at: nil>]

7 Foo.where("updated_at != '0000-00-00 00:00:00'") # => [#<Foo:0x000056314a8d7878 id: 1, num: 15, created_at: 2020-06-22 11:23:40 UTC, updated_at: 2020-06-22 11:23:48 UTC>]
  • Foo.all returns all default ('0000-00-00 00:00:00') updated_at columns as nil.
  • On line 2 I try to get rows where updated_at is nil by passing a hash then I get an empty array. Then on lines 4 and 5 I try to get rows where updated_at is either '0000-00-00 00:00:00' or not. I still get empty arrays for both queries.
  • Passing a string like on lines 6 and 7 seems to work as expected.
+------------------------------------------------------------------------------------------------------------------------------+
| @@global.sql_mode                                                                                                            |
+------------------------------------------------------------------------------------------------------------------------------+
| ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION |
+------------------------------------------------------------------------------------------------------------------------------+

+------------------------------------------------------------------------------------------------------------------------------+
| @@session.sql_mode                                                                                                           |
+------------------------------------------------------------------------------------------------------------------------------+
| ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION |
+------------------------------------------------------------------------------------------------------------------------------+

+-------------------------+
| @@version               |
+-------------------------+
| 5.7.30-0ubuntu0.18.04.1 |
+-------------------------+

My questions

  1. Is it the normal behavior that you get nils when the timestamp is 0000-00-00 00:00:00?
  2. Why didn't the code on lines 4 and 5 work as expected?
1 Answers

You should let ActiveRecord handle these updates for you. You don't need to use migrations, just have the columns without any default values.

CREATE TABLE foo(
  id INT PRIMARY KEY AUTO_INCREMENT,
  num INT,
  created_at TIMESTAMP NOT NULL,
  updated_at TIMESTAMP NOT NULL
);

then ActiveRecord will automatically fill these values on saving and updating.

Related