6
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

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

Posted at

はじめに

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

参考情報

6
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?