Posted at

Rails6 のちょい足しな新機能を試す65(timestamps precision編)


はじめに

Rails 6 に追加されそうな新機能を試す第65段。 今回は、 timestamps precision 編です。

Rails 6 では、 timestamps にデフォルトで、 precision が設定されるようになりました。

Ruby 2.6.3, Rails 6.0.0.rc1, Rails 5.2.3, MySQL 8.0.16 で確認しました。Rails 6.0.0.rc1 は gem install rails --prerelease でインストールできます。

$ rails --version

Rails 6.0.0.rc1

今回は、 created_at を検索条件にして検索してみます。


プロジェクトを作る

rails new rails6_0_0rc1

cd rails6_0_0rc1


model を作る

User モデルを作ります。

bin/rails g model User name


seed データを作る

1件だけですが、 seed データを作成します。


db/seeds.rb

User.create(name: 'Taro')



User モデルを修正する

User モデルに scope を1つ作ります。


  1. 1件目のデータの created_at カラムを取得します。

  2. created_at カラムから 秒まで指定した Time オブジェクトを作る。

  3. Timeオブジェクトを条件にして、 created_at で検索する。


app/models/user.rb

class User < ApplicationRecord

scope :find_first, -> {
created_at = first.created_at
t = Time.new(created_at.year, created_at.month, created_at.day, created_at.hour, created_at.min, created_at.sec)
where(created_at: t)
}
end


seed データを登録します。

$ bin/rails db:create db:migrate db:seed


rails console で確認する

rails console で確認してみます。

irb(main):001:0> User.find_first

(0.4ms) SET NAMES utf8mb4, @@SESSION.sql_mode = CONCAT(CONCAT(@@sql_mode, ',STRICT_ALL_TABLES'), ',NO_AUTO_VALUE_ON_ZERO'), @@SESSION.sql_auto_is_null = 0, @@SESSION.wait_timeout = 2147483
User Load (0.4ms) SELECT `users`.* FROM `users` ORDER BY `users`.`id` ASC LIMIT 1
User Load (0.3ms) SELECT `users`.* FROM `users` WHERE `users`.`created_at` = '2019-07-26 06:52:38' LIMIT 11
=> #<ActiveRecord::Relation []>

データは見つかりませんでした。


mysql で検索してみる

mysql で検索してみます。

mysql> select * from users;

+----+------+----------------------------+----------------------------+
| id | name | created_at | updated_at |
+----+------+----------------------------+----------------------------+
| 1 | Taro | 2019-07-26 06:52:38.606642 | 2019-07-26 06:52:38.606642 |
+----+------+----------------------------+----------------------------+
1 row in set (0.00 sec)

created_atupdated_at の秒に6桁の小数部分が存在していることが確認できます。


schema.rb を確認する

schema.rb を確認すると precision: 6 が指定されていることがわかります。


db/schema.rb

  ...

create_table "users", options: "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci", force: :cascade do |t|
t.string "name"
t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
end
...


Rails 5 では

Rails 5.2.3 では、データが検索できます。

irb(main):001:0> User.find_first

(0.7ms) SET NAMES utf8mb4, @@SESSION.sql_mode = CONCAT(CONCAT(@@sql_mode, ',STRICT_ALL_TABLES'), ',NO_AUTO_VALUE_ON_ZERO'), @@SESSION.sql_auto_is_null = 0, @@SESSION.wait_timeout = 2147483
User Load (0.3ms) SELECT `users`.* FROM `users` ORDER BY `users`.`id` ASC LIMIT 1
User Load (0.4ms) SELECT `users`.* FROM `users` WHERE `users`.`created_at` = '2019-07-26 06:42:34' LIMIT 11
=> #<ActiveRecord::Relation [#<User id: 1, name: "Taro", created_at: "2019-07-26 06:42:34", updated_at: "2019-07-26 06:42:34">]>

MySQL で確認すると、秒に小数部分がありません。

mysql> select * from users;

+----+------+---------------------+---------------------+
| id | name | created_at | updated_at |
+----+------+---------------------+---------------------+
| 1 | Taro | 2019-07-26 06:42:34 | 2019-07-26 06:42:34 |
+----+------+---------------------+---------------------+
1 row in set (0.00 sec)

schema.rb にも precision: 6 がありません。


db/schema.rb

  ...

create_table "users", options: "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci", force: :cascade do |t|
t.string "name"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
...


Rails 6 でデータを見つけるには

十分な検証はしてませんが、 created_at.subsec を考慮してやれば良さそうです。


app/models/user.rb

class User < ApplicationRecord

scope :find_first, -> {
created_at = first.created_at
# t = Time.new(created_at.year, created_at.month, created_at.day, created_at.hour, created_at.min, created_at.sec)
t = Time.new(created_at.year, created_at.month, created_at.day, created_at.hour, created_at.min, created_at.sec) + created_at.subsec
where(created_at: t)
}
end


試したソース

試したソースは以下にあります。

https://github.com/suketa/rails6_0_0rc1/tree/try065_mysql_precision


参考情報