💡

【Rails】カラム修飾子 precision について

2024/04/25に公開

はじめに

お疲れ様です!
おおくまです!

今回は、「【Rails】カラム修飾子 precision について」ということで、Ruby on Railsのカラム修飾子であるprecisionについてまとめてみました!

少しでも皆様の参考になりますと幸いです!

対象読者

注意点

環境

precisionとは

precisionとは、カラム修飾子の1つで、decimal/numeric/datetime/timeフィールドの精度(precision)を定義するものです!
具体的には、小数点以下の桁数を指定するもので、最大6桁まで指定することができます!
このprecisionをどのように定義するのか、または定義しないのか、によって、レコードに保存される値が変わってきます!

https://railsguides.jp/active_record_migrations.html#カラム修飾子

具体例

今回は以下の3つのテーブルを作成し、それぞれ異なるパターンでprecisionを適用し、どのように値が保存されるのか比較してみました!

db/migrate/20240421005254_create_posts.rb
class CreatePosts < ActiveRecord::Migration[7.0]
  def change
    create_table :posts do |t|
      t.datetime :published_at, null: false
      t.timestamps
    end
  end
end
db/migrate/20240421014454_create_articles.rb
class CreateArticles < ActiveRecord::Migration[7.0]
  def change
    create_table :articles do |t|
      t.datetime :published_at, precision: 0, null: false
      t.timestamps
    end
  end
end
db/migrate/20240421014622_create_comments.rb
class CreateComments < ActiveRecord::Migration[7.0]
  def change
    create_table :comments do |t|
      t.datetime :published_at, precision: nil, null: false
      t.timestamps
    end
  end
end
db/schema.rb
ActiveRecord::Schema[7.0].define(version: 2024_04_21_014622) do
  create_table "articles", force: :cascade do |t|
    t.datetime "published_at", precision: 0, null: false
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
  end

  create_table "comments", force: :cascade do |t|
    t.datetime "published_at", precision: nil, null: false
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
  end

  create_table "posts", force: :cascade do |t|
    t.datetime "published_at", null: false
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
  end
end

コンソールでそれぞれのpublished_atにどのように値が保存されるか確認してみます!

docker-compose exec app rails c
Loading development environment (Rails 7.0.8)

[1] pry(main)> now = Time.zone.now
=> Sun, 21 Apr 2024 11:21:47.147958377 JST +09:00

[2] pry(main)> Post.create(published_at: now)
  TRANSACTION (0.1ms)  BEGIN
  Post Create (0.7ms)  INSERT INTO "posts" ("published_at", "created_at", "updated_at") VALUES ($1, $2, $3) RETURNING "id"  [["published_at", "2024-04-21 02:21:47.147958"], ["created_at", "2024-04-21 02:21:54.776314"], ["updated_at", "2024-04-21 02:21:54.776314"]]
  TRANSACTION (0.2ms)  COMMIT
=> #<Post:0x0000ffff8b6d0070
 id: 1,
 published_at: Sun, 21 Apr 2024 11:21:47.147958000 JST +09:00,
 created_at: Sun, 21 Apr 2024 11:21:54.776314000 JST +09:00,
 updated_at: Sun, 21 Apr 2024 11:21:54.776314000 JST +09:00>

[3] pry(main)> Article.create(published_at: now)
  TRANSACTION (0.3ms)  BEGIN
  Article Create (1.4ms)  INSERT INTO "articles" ("published_at", "created_at", "updated_at") VALUES ($1, $2, $3) RETURNING "id"  [["published_at", "2024-04-21 02:21:47"], ["created_at", "2024-04-21 02:21:57.198532"], ["updated_at", "2024-04-21 02:21:57.198532"]]
  TRANSACTION (0.9ms)  COMMIT
=> #<Article:0x0000ffff8b621c00
 id: 1,
 published_at: Sun, 21 Apr 2024 11:21:47.000000000 JST +09:00,
 created_at: Sun, 21 Apr 2024 11:21:57.198532000 JST +09:00,
 updated_at: Sun, 21 Apr 2024 11:21:57.198532000 JST +09:00>

[4] pry(main)> Comment.create(published_at: now)
  TRANSACTION (0.2ms)  BEGIN
  Comment Create (1.3ms)  INSERT INTO "comments" ("published_at", "created_at", "updated_at") VALUES ($1, $2, $3) RETURNING "id"  [["published_at", "2024-04-21 02:21:47.147958"], ["created_at", "2024-04-21 02:21:59.266544"], ["updated_at", "2024-04-21 02:21:59.266544"]]
  TRANSACTION (1.0ms)  COMMIT
=> #<Comment:0x0000ffff8b5e3040
 id: 1,
 published_at: Sun, 21 Apr 2024 11:21:47.147958377 JST +09:00,
 created_at: Sun, 21 Apr 2024 11:21:59.266544000 JST +09:00,
 updated_at: Sun, 21 Apr 2024 11:21:59.266544000 JST +09:00>

nowと、それぞれのpublished_atの値はこのようになりました!

  • now

    • Sun, 21 Apr 2024 11:21:47.147958377 JST +09:00
  • Post

    • Sun, 21 Apr 2024 11:21:47.147958000 JST +09:00
    • precisionを特に指定しなかった場合は、小数点以下6桁まで値が保存されています!
    • 私の環境では、precisionを指定していない場合はprecision: 6と設定されました!
    • 調べたところ、Rails 7.0.2以降では、precisionを指定していない場合、precision: 6と読み替えるようです!
  • Article

    • Sun, 21 Apr 2024 11:21:47.000000000 JST +09:00
    • こちらは、precision: 0と指定しているので、小数点以下は値が保存されていません!
  • Comment

    • Sun, 21 Apr 2024 11:21:47.147958377 JST +09:00
    • こちらは、precision: nilと指定した結果、このようになりました!
    • 調べたところ、precision: nilと指定した場合は、各環境のデータベースのデフォルトに設定されるようです!
    • コンソール上では、小数点以下9桁までしか表示されていないので、nowと保存されている値が同じに見えますが、比較してみると値は違うみたいです!
    [5] pry(main)> now == Comment.first.published_at
      Comment Load (0.2ms)  SELECT "comments".* FROM "comments" ORDER BY "comments"."id" ASC LIMIT $1  [["LIMIT", 1]]
    => false
    

このようにprecisionをどのように適用するのかによって保存される値が変わってきますので、テーブル作成やカラム追加の際には注意が必要です!

また、precisionは、Railsのバージョンによっても、挙動が変わってくるので、下記の記事を参考にしてみてください!

https://zenn.dev/bisque/scraps/6ff905748302e4

さいごに

今回、precisionについてまとめてみましたが、私はこれを知らなかったために、通るはずのRSpecが通らず苦労しました。笑
今後、テーブル作成やカラム追加の際には注意したいと思います!
最後まで読んでいただき、ありがとうございました!

参考文献

https://kossy-web-engineer.hatenablog.com/entry/2020/12/13/111823

GitHubで編集を提案
株式会社リンクエッジ

Discussion