📑

Railsでデフォルト生成されたIDカラムの上限値

2021/07/19に公開

対象読者

・RailsのIDカラムの上限値を知りたい人
・モデルの型定義について知りたい人

結論(デフォルト生成されたIDカラムの上限値)

※ PostgreSQLを使用する場合

Rails5.1未満で作成済みのマイグレーションファイルで作成したテーブル

# マイグレーションファイルの継承元が[5.1]未満
class **** < ActiveRecord::Migration[5.0]

idは serial型 で定義される為、4バイトの 2147483648 以上 の値を設定し、保存するときにエラー発生

Rails5.1以降で作成済みのマイグレーションファイルで作成したテーブル

# マイグレーションファイルの継承元が[5.1]以降
class **** < ActiveRecord::Migration[5.1]

idは bigserial型 で定義される為、8バイトの 9223372036854775808 以上 の値を設定し、保存するときにエラー発生

実験

上限値を入力してエラーを発生させてみる

serial型 の場合

# 2147483647 だとOK
pry(main)> Author.new(id: 2147483647).save
(0.3ms)  BEGIN
Author Create (0.5ms)  INSERT INTO "authors" ("id", "created_at", "updated_at") VALUES ($1, $2, $3)  [["id", 2147483647], ["created_at", "2021-07-16 10:36:18.537225"], ["updated_at", "2021-07-16 10:36:18.537225"]]
SQL (0.2ms)  SELECT currval('public.authors_id_seq')
(0.5ms)  COMMIT
’=> true

# 4バイトの 2147483648 でエラー発生
pry(main)> Author.new(id: 2147483648).save
(0.2ms)  BEGIN
(0.2ms)  ROLLBACK
ActiveModel::RangeError: 2147483648 is out of range for ActiveModel::Type::Integer with limit 4 bytes
from **********/vendor/bundle/ruby/2.6.0/gems/activemodel-5.2.4.3/lib/active_model/type/integer.rb:53:in `ensure_in_range'

# SELECT setval('authors_id_seq', 2147483647);
# シーケンスを上限値に設定して保存するとエラー発生
pry(main)> Author.new(creator_id: 0, updater_id: 0).save
(16.0ms)  BEGIN
Author Create (33.4ms)  INSERT INTO "authors" ("created_at", "updated_at") VALUES ($1, $2)  [["created_at", "2021-07-16 13:05:52.178741"], ["updated_at", "2021-07-16 13:05:52.178741"]]
(6.1ms)  ROLLBACK
ActiveRecord::StatementInvalid: PG::DataException: ERROR:  nextval: reached maximum value of sequence "authors_id_seq" (2147483647)
: INSERT INTO "authors" ("created_at", "updated_at", "creator_id", "updater_id") VALUES ($1, $2)
from **********/vendor/bundle/ruby/2.6.0/gems/activerecord-5.2.4.3/lib/active_record/connection_adapters/postgresql_adapter.rb:611:in `async_exec'
Caused by PG::DataException: ERROR:  nextval: reached maximum value of sequence "authors_id_seq" (2147483647)

bigserial型 の場合

# 8バイトの 9223372036854775808 でエラー発生
[1] pry(main)> Book.new(id: 9223372036854775808, name: 'hoge').save
(0.1ms)  BEGIN
(0.1ms)  ROLLBACK
ActiveModel::RangeError: 9223372036854775808 is out of range for ActiveModel::Type::Integer with limit 8 bytes
from **********/vendor/bundle/ruby/2.6.0/gems/activemodel-5.2.4.4/lib/active_model/type/integer.rb:53:in `ensure_in_range'

その他の調査ログ

それっぽいところで callerメソッドを実行して、呼び元を確認してみる

 "*********/vendor/bundle/ruby/2.6.0/gems/activerecord-5.2.4.4/lib/active_record/connection_adapters/postgresql_adapter.rb:452:in `get_oid_type'",
 "*********/vendor/bundle/ruby/2.6.0/gems/activerecord-5.2.4.4/lib/active_record/connection_adapters/postgresql/schema_statements.rb:668:in `fetch_type_metadata'",
 "*********/vendor/bundle/ruby/2.6.0/gems/activerecord-5.2.4.4/lib/active_record/connection_adapters/postgresql/schema_statements.rb:649:in `new_column_from_field'",
 "*********/vendor/bundle/ruby/2.6.0/gems/activerecord-5.2.4.4/lib/active_record/connection_adapters/abstract/schema_statements.rb:114:in `block in columns'",
 "*********/vendor/bundle/ruby/2.6.0/gems/activerecord-5.2.4.4/lib/active_record/connection_adapters/abstract/schema_statements.rb:113:in `map'",
 "*********/vendor/bundle/ruby/2.6.0/gems/activerecord-5.2.4.4/lib/active_record/connection_adapters/abstract/schema_statements.rb:113:in `columns'",
 "*********/vendor/bundle/ruby/2.6.0/gems/activerecord-5.2.4.4/lib/active_record/connection_adapters/schema_cache.rb:69:in `columns'",
 "*********/vendor/bundle/ruby/2.6.0/gems/activerecord-5.2.4.4/lib/active_record/connection_adapters/schema_cache.rb:75:in `columns_hash'",
 "*********/vendor/bundle/ruby/2.6.0/gems/activerecord-5.2.4.4/lib/active_record/model_schema.rb:466:in `load_schema!'",
 "*********/vendor/bundle/ruby/2.6.0/gems/activerecord-5.2.4.4/lib/active_record/attributes.rb:234:in `load_schema!'",
 "*********/vendor/bundle/ruby/2.6.0/gems/activerecord-5.2.4.4/lib/active_record/attribute_decorators.rb:51:in `load_schema!'",
 "*********/vendor/bundle/ruby/2.6.0/gems/activerecord-5.2.4.4/lib/active_record/model_schema.rb:459:in `block in load_schema'",
 "*********/.rbenv/versions/2.6.6/lib/ruby/2.6.0/monitor.rb:235:in `mon_synchronize'",
 "*********/vendor/bundle/ruby/2.6.0/gems/activerecord-5.2.4.4/lib/active_record/model_schema.rb:456:in `load_schema'",
 "*********/vendor/bundle/ruby/2.6.0/gems/activerecord-5.2.4.4/lib/active_record/model_schema.rb:346:in `attribute_types'",
 "*********/vendor/bundle/ruby/2.6.0/gems/activerecord-5.2.4.4/lib/active_record/attribute_methods.rb:230:in `has_attribute?'",
 "*********/vendor/bundle/ruby/2.6.0/gems/activerecord-5.2.4.4/lib/active_record/inheritance.rb:55:in `new'",
 "*********/app/controllers/books_controller.rb:9:in `create'",

get_oid_typeを見てみると、、

activerecord-5.2.4.4/lib/active_record/connection_adapters/postgresql_adapter.rb
        def get_oid_type(oid, fmod, column_name, sql_type = "".freeze)
          if !type_map.key?(oid)
            load_additional_types([oid])
          end

          type_map.fetch(oid, fmod, sql_type) {
            warn "unknown OID #{oid}: failed to recognize type of '#{column_name}'. It will be treated as String."
            Type.default_value.tap do |cast_type|
              type_map.register_type(oid, cast_type)
            end
          }
        end

type_mapfetchすると型を取得できるぽい
bigserialの場合 ↓↓↓

[8] pry(#<ActiveRecord::ConnectionAdapters::PostgreSQLAdapter>)> type_map.fetch(oid, fmod, sql_type)
=> #<ActiveModel::Type::Integer:0x00007fdb07db2650 @limit=8, @precision=nil, @range=-9223372036854775808...9223372036854775808, @scale=nil>


[9] pry(#<ActiveRecord::ConnectionAdapters::PostgreSQLAdapter>)> oid
=> 20
[10] pry(#<ActiveRecord::ConnectionAdapters::PostgreSQLAdapter>)> fmod
=> -1
[11] pry(#<ActiveRecord::ConnectionAdapters::PostgreSQLAdapter>)> sql_type
=> "bigint"

いつの間にか取得されているbigintoidなどの情報はcolumn_definitionsで取得するぽい

activerecord-5.2.4.4/lib/active_record/connection_adapters/postgresql_adapter.rb
        def column_definitions(table_name)
          query(<<-end_sql, "SCHEMA")
              SELECT a.attname, format_type(a.atttypid, a.atttypmod),
                     pg_get_expr(d.adbin, d.adrelid), a.attnotnull, a.atttypid, a.atttypmod,
                     c.collname, col_description(a.attrelid, a.attnum) AS comment
                FROM pg_attribute a
                LEFT JOIN pg_attrdef d ON a.attrelid = d.adrelid AND a.attnum = d.adnum
                LEFT JOIN pg_type t ON a.atttypid = t.oid
                LEFT JOIN pg_collation c ON a.attcollation = c.oid AND a.attcollation <> t.typcollation
               WHERE a.attrelid = #{quote(quote_table_name(table_name))}::regclass
                 AND a.attnum > 0 AND NOT a.attisdropped
               ORDER BY a.attnum
          end_sql
        end

テーブルカラムの定義情報の取得

SQLクライアントで実行してみると、、、

SELECT a.attname, format_type(a.atttypid, a.atttypmod),
         pg_get_expr(d.adbin, d.adrelid), a.attnotnull, a.atttypid, a.atttypmod,
         c.collname, col_description(a.attrelid, a.attnum) AS comment
    FROM pg_attribute a
    LEFT JOIN pg_attrdef d ON a.attrelid = d.adrelid AND a.attnum = d.adnum
    LEFT JOIN pg_type t ON a.atttypid = t.oid
    LEFT JOIN pg_collation c ON a.attcollation = c.oid AND a.attcollation <> t.typcollation
   WHERE a.attrelid = 'books'::regclass
     AND a.attnum > 0 AND NOT a.attisdropped
   ORDER BY a.attnum

-- 以下のような結果がテーブル定義を取得できる
attname   |format_type                |pg_get_expr                      |attnotnull|atttypid|atttypmod|collname|comment|
----------+---------------------------+---------------------------------+----------+--------+---------+--------+-------+
id        |bigint                     |nextval('books_id_seq'::regclass)|true      |      20|       -1|        |       |
name      |character varying          |                                 |false     |    1043|       -1|        |       |
created_at|timestamp without time zone|                                 |true      |    1114|       -1|        |       |
updated_at|timestamp without time zone|                                 |true      |    1114|       -1|        |       |

モデルの型決定に使用する変換用のマッピング情報

type_mapはDB接続時に作成されるぽい

activerecord-5.2.4.4/lib/active_record/connection_adapters/postgresql_adapter.rb
# 48行目 postgresql_connection
ConnectionAdapters::PostgreSQLAdapter.new(nil, logger, conn_params, config)

# 234行目 initialize
@type_map = Type::HashLookupTypeMap.new
initialize_type_map

# 460行目 initialize_type_map
def initialize_type_map(m = type_map)
  m.register_type "int2", Type::Integer.new(limit: 2)
  m.register_type "int4", Type::Integer.new(limit: 4)
  m.register_type "int8", Type::Integer.new(limit: 8)
  m.register_type "oid", OID::Oid.new
  # ...省略

type_mapにはこんなの↓↓↓が入っていて、oidをキーにProcを取得している

長すぎる type_map の内容をクリックして展開
[6] pry(#<ActiveRecord::ConnectionAdapters::PostgreSQLAdapter>)> type_map
=> #<ActiveRecord::Type::HashLookupTypeMap:0x00007fdb07db2a10
 @cache=#<Concurrent::Map:0x00007fdb07db29c0 entries=4 default_proc=#<Proc:0x00007fdb07db2920@/*************/vendor/bundle/ruby/2.6.0/gems/activerecord-5.2.4.4/lib/active_record/type/type_map.rb:10>>,
 @mapping=
  {"int2"=>#<Proc:0x00007fdb07db27e0@/*********/vendor/bundle/ruby/2.6.0/gems/activerecord-5.2.4.4/lib/active_record/type/type_map.rb:32>,
   "int4"=>#<Proc:0x00007fdb07db26a0@/*********/vendor/bundle/ruby/2.6.0/gems/activerecord-5.2.4.4/lib/active_record/type/type_map.rb:32>,
   "int8"=>#<Proc:0x00007fdb07db2498@/*********/vendor/bundle/ruby/2.6.0/gems/activerecord-5.2.4.4/lib/active_record/type/type_map.rb:32>,
   "oid"=>#<Proc:0x00007fdb07db23d0@/*********/vendor/bundle/ruby/2.6.0/gems/activerecord-5.2.4.4/lib/active_record/type/type_map.rb:32>,
   "float4"=>#<Proc:0x00007fdb07db2358@/*********/vendor/bundle/ruby/2.6.0/gems/activerecord-5.2.4.4/lib/active_record/type/type_map.rb:32>,
   "float8"=>#<Proc:0x00007fdb07db2308@/*********/vendor/bundle/ruby/2.6.0/gems/activerecord-5.2.4.4/lib/active_record/type/hash_lookup_type_map.rb:7>,
   "text"=>#<Proc:0x00007fdb07db2290@/*********/vendor/bundle/ruby/2.6.0/gems/activerecord-5.2.4.4/lib/active_record/type/type_map.rb:32>,
   "varchar"=>#<Proc:0x00007fdb07db2240@/*********/vendor/bundle/ruby/2.6.0/gems/activerecord-5.2.4.4/lib/active_record/connection_adapters/abstract_adapter.rb:530>,
   "char"=>#<Proc:0x00007fdb07db21f0@/*********/vendor/bundle/ruby/2.6.0/gems/activerecord-5.2.4.4/lib/active_record/type/hash_lookup_type_map.rb:7>,
   "name"=>#<Proc:0x00007fdb07db21a0@/*********/vendor/bundle/ruby/2.6.0/gems/activerecord-5.2.4.4/lib/active_record/type/hash_lookup_type_map.rb:7>,
   "bpchar"=>#<Proc:0x00007fdb07db2150@/*********/vendor/bundle/ruby/2.6.0/gems/activerecord-5.2.4.4/lib/active_record/type/hash_lookup_type_map.rb:7>,
   "bool"=>#<Proc:0x00007fdb07db20d8@/*********/vendor/bundle/ruby/2.6.0/gems/activerecord-5.2.4.4/lib/active_record/type/type_map.rb:32>,
   "bit"=>#<Proc:0x00007fdb07db2088@/*********/vendor/bundle/ruby/2.6.0/gems/activerecord-5.2.4.4/lib/active_record/connection_adapters/abstract_adapter.rb:530>,
   "varbit"=>#<Proc:0x00007fdb07db2038@/*********/vendor/bundle/ruby/2.6.0/gems/activerecord-5.2.4.4/lib/active_record/connection_adapters/abstract_adapter.rb:530>,
   "timestamptz"=>#<Proc:0x00007fdb07db1fe8@/*********/vendor/bundle/ruby/2.6.0/gems/activerecord-5.2.4.4/lib/active_record/type/hash_lookup_type_map.rb:7>,
   "date"=>#<Proc:0x00007fdb07db1f70@/*********/vendor/bundle/ruby/2.6.0/gems/activerecord-5.2.4.4/lib/active_record/type/type_map.rb:32>,
   "money"=>#<Proc:0x00007fdb07db1ef8@/*********/vendor/bundle/ruby/2.6.0/gems/activerecord-5.2.4.4/lib/active_record/type/type_map.rb:32>,
   "bytea"=>#<Proc:0x00007fdb07db1e80@/*********/vendor/bundle/ruby/2.6.0/gems/activerecord-5.2.4.4/lib/active_record/type/type_map.rb:32>,
   "point"=>#<Proc:0x00007fdb07db1e08@/*********/vendor/bundle/ruby/2.6.0/gems/activerecord-5.2.4.4/lib/active_record/type/type_map.rb:32>,
   "hstore"=>#<Proc:0x00007fdb07db1d90@/*********/vendor/bundle/ruby/2.6.0/gems/activerecord-5.2.4.4/lib/active_record/type/type_map.rb:32>,
   "json"=>#<Proc:0x00007fdb07db1d18@/*********/vendor/bundle/ruby/2.6.0/gems/activerecord-5.2.4.4/lib/active_record/type/type_map.rb:32>,
   "jsonb"=>#<Proc:0x00007fdb07db1ca0@/*********/vendor/bundle/ruby/2.6.0/gems/activerecord-5.2.4.4/lib/active_record/type/type_map.rb:32>,
   "cidr"=>#<Proc:0x00007fdb07db1c28@/*********/vendor/bundle/ruby/2.6.0/gems/activerecord-5.2.4.4/lib/active_record/type/type_map.rb:32>,
   "inet"=>#<Proc:0x00007fdb07db1bb0@/*********/vendor/bundle/ruby/2.6.0/gems/activerecord-5.2.4.4/lib/active_record/type/type_map.rb:32>,
   "uuid"=>#<Proc:0x00007fdb07db1b38@/*********/vendor/bundle/ruby/2.6.0/gems/activerecord-5.2.4.4/lib/active_record/type/type_map.rb:32>,
   "xml"=>#<Proc:0x00007fdb07db1ac0@/*********/vendor/bundle/ruby/2.6.0/gems/activerecord-5.2.4.4/lib/active_record/type/type_map.rb:32>,
   "tsvector"=>#<Proc:0x00007fdb07db1a20@/*********/vendor/bundle/ruby/2.6.0/gems/activerecord-5.2.4.4/lib/active_record/type/type_map.rb:32>,
   "macaddr"=>#<Proc:0x00007fdb07db1980@/*********/vendor/bundle/ruby/2.6.0/gems/activerecord-5.2.4.4/lib/active_record/type/type_map.rb:32>,
   "citext"=>#<Proc:0x00007fdb07db18e0@/*********/vendor/bundle/ruby/2.6.0/gems/activerecord-5.2.4.4/lib/active_record/type/type_map.rb:32>,
   "ltree"=>#<Proc:0x00007fdb07db1840@/*********/vendor/bundle/ruby/2.6.0/gems/activerecord-5.2.4.4/lib/active_record/type/type_map.rb:32>,
   "line"=>#<Proc:0x00007fdb07db17a0@/*********/vendor/bundle/ruby/2.6.0/gems/activerecord-5.2.4.4/lib/active_record/type/type_map.rb:32>,
   "lseg"=>#<Proc:0x00007fdb07db1700@/*********/vendor/bundle/ruby/2.6.0/gems/activerecord-5.2.4.4/lib/active_record/type/type_map.rb:32>,
   "box"=>#<Proc:0x00007fdb07db1660@/*********/vendor/bundle/ruby/2.6.0/gems/activerecord-5.2.4.4/lib/active_record/type/type_map.rb:32>,
   "path"=>#<Proc:0x00007fdb07db15c0@/*********/vendor/bundle/ruby/2.6.0/gems/activerecord-5.2.4.4/lib/active_record/type/type_map.rb:32>,
   "polygon"=>#<Proc:0x00007fdb07db1520@/*********/vendor/bundle/ruby/2.6.0/gems/activerecord-5.2.4.4/lib/active_record/type/type_map.rb:32>,
   "circle"=>#<Proc:0x00007fdb07db1480@/*********/vendor/bundle/ruby/2.6.0/gems/activerecord-5.2.4.4/lib/active_record/type/type_map.rb:32>,
   "interval"=>#<Proc:0x00007fdb07db1430@/*********/vendor/bundle/ruby/2.6.0/gems/activerecord-5.2.4.4/lib/active_record/connection_adapters/postgresql_adapter.rb:499>,
   "time"=>#<Proc:0x00007fdb07db13e0@/*********/vendor/bundle/ruby/2.6.0/gems/activerecord-5.2.4.4/lib/active_record/connection_adapters/abstract_adapter.rb:537>,
   "timestamp"=>#<Proc:0x00007fdb07db1390@/*********/vendor/bundle/ruby/2.6.0/gems/activerecord-5.2.4.4/lib/active_record/connection_adapters/abstract_adapter.rb:537>,
   "numeric"=>#<Proc:0x00007fdb07db1368@/*********/vendor/bundle/ruby/2.6.0/gems/activerecord-5.2.4.4/lib/active_record/connection_adapters/postgresql_adapter.rb:507>,
   16=>#<Proc:0x00007fdb0be6dac8@/*********/vendor/bundle/ruby/2.6.0/gems/activerecord-5.2.4.4/lib/active_record/type/hash_lookup_type_map.rb:7>,
   17=>#<Proc:0x00007fdb0be6da78@/*********/vendor/bundle/ruby/2.6.0/gems/activerecord-5.2.4.4/lib/active_record/type/hash_lookup_type_map.rb:7>,
   18=>#<Proc:0x00007fdb0be6da28@/*********/vendor/bundle/ruby/2.6.0/gems/activerecord-5.2.4.4/lib/active_record/type/hash_lookup_type_map.rb:7>,
   19=>#<Proc:0x00007fdb0be6d9d8@/*********/vendor/bundle/ruby/2.6.0/gems/activerecord-5.2.4.4/lib/active_record/type/hash_lookup_type_map.rb:7>,
   20=>#<Proc:0x00007fdb0be6d988@/*********/vendor/bundle/ruby/2.6.0/gems/activerecord-5.2.4.4/lib/active_record/type/hash_lookup_type_map.rb:7>,
   21=>#<Proc:0x00007fdb0be6d938@/*********/vendor/bundle/ruby/2.6.0/gems/activerecord-5.2.4.4/lib/active_record/type/hash_lookup_type_map.rb:7>,
   23=>#<Proc:0x00007fdb0be6d8e8@/*********/vendor/bundle/ruby/2.6.0/gems/activerecord-5.2.4.4/lib/active_record/type/hash_lookup_type_map.rb:7>,
   25=>#<Proc:0x00007fdb0be6d898@/*********/vendor/bundle/ruby/2.6.0/gems/activerecord-5.2.4.4/lib/active_record/type/hash_lookup_type_map.rb:7>,
   26=>#<Proc:0x00007fdb0be6d848@/*********/vendor/bundle/ruby/2.6.0/gems/activerecord-5.2.4.4/lib/active_record/type/hash_lookup_type_map.rb:7>,
   114=>#<Proc:0x00007fdb0be6d7f8@/*********/vendor/bundle/ruby/2.6.0/gems/activerecord-5.2.4.4/lib/active_record/type/hash_lookup_type_map.rb:7>,
   142=>#<Proc:0x00007fdb0be6d7a8@/*********/vendor/bundle/ruby/2.6.0/gems/activerecord-5.2.4.4/lib/active_record/type/hash_lookup_type_map.rb:7>,
   600=>#<Proc:0x00007fdb0be6d758@/*********/vendor/bundle/ruby/2.6.0/gems/activerecord-5.2.4.4/lib/active_record/type/hash_lookup_type_map.rb:7>,
   601=>#<Proc:0x00007fdb0be6d708@/*********/vendor/bundle/ruby/2.6.0/gems/activerecord-5.2.4.4/lib/active_record/type/hash_lookup_type_map.rb:7>,
   602=>#<Proc:0x00007fdb0be6d6b8@/*********/vendor/bundle/ruby/2.6.0/gems/activerecord-5.2.4.4/lib/active_record/type/hash_lookup_type_map.rb:7>,
   603=>#<Proc:0x00007fdb0be6d668@/*********/vendor/bundle/ruby/2.6.0/gems/activerecord-5.2.4.4/lib/active_record/type/hash_lookup_type_map.rb:7>,
   604=>#<Proc:0x00007fdb0be6d618@/*********/vendor/bundle/ruby/2.6.0/gems/activerecord-5.2.4.4/lib/active_record/type/hash_lookup_type_map.rb:7>,
   628=>#<Proc:0x00007fdb0be6d5c8@/*********/vendor/bundle/ruby/2.6.0/gems/activerecord-5.2.4.4/lib/active_record/type/hash_lookup_type_map.rb:7>,
   700=>#<Proc:0x00007fdb0be6d578@/*********/vendor/bundle/ruby/2.6.0/gems/activerecord-5.2.4.4/lib/active_record/type/hash_lookup_type_map.rb:7>,
   701=>#<Proc:0x00007fdb0be6d528@/*********/vendor/bundle/ruby/2.6.0/gems/activerecord-5.2.4.4/lib/active_record/type/hash_lookup_type_map.rb:7>,
   718=>#<Proc:0x00007fdb0be6d4d8@/*********/vendor/bundle/ruby/2.6.0/gems/activerecord-5.2.4.4/lib/active_record/type/hash_lookup_type_map.rb:7>,
   790=>#<Proc:0x00007fdb0be6d488@/*********/vendor/bundle/ruby/2.6.0/gems/activerecord-5.2.4.4/lib/active_record/type/hash_lookup_type_map.rb:7>,
   829=>#<Proc:0x00007fdb0be6d438@/*********/vendor/bundle/ruby/2.6.0/gems/activerecord-5.2.4.4/lib/active_record/type/hash_lookup_type_map.rb:7>,
   869=>#<Proc:0x00007fdb0be6d3e8@/*********/vendor/bundle/ruby/2.6.0/gems/activerecord-5.2.4.4/lib/active_record/type/hash_lookup_type_map.rb:7>,
   650=>#<Proc:0x00007fdb0be6d398@/*********/vendor/bundle/ruby/2.6.0/gems/activerecord-5.2.4.4/lib/active_record/type/hash_lookup_type_map.rb:7>,
   1042=>#<Proc:0x00007fdb0be6d348@/*********/vendor/bundle/ruby/2.6.0/gems/activerecord-5.2.4.4/lib/active_record/type/hash_lookup_type_map.rb:7>,
   1043=>#<Proc:0x00007fdb0be6d2f8@/*********/vendor/bundle/ruby/2.6.0/gems/activerecord-5.2.4.4/lib/active_record/type/hash_lookup_type_map.rb:7>,
   1082=>#<Proc:0x00007fdb0be6d2a8@/*********/vendor/bundle/ruby/2.6.0/gems/activerecord-5.2.4.4/lib/active_record/type/hash_lookup_type_map.rb:7>,
   1083=>#<Proc:0x00007fdb0be6d258@/*********/vendor/bundle/ruby/2.6.0/gems/activerecord-5.2.4.4/lib/active_record/type/hash_lookup_type_map.rb:7>,
   1114=>#<Proc:0x00007fdb0be6d208@/*********/vendor/bundle/ruby/2.6.0/gems/activerecord-5.2.4.4/lib/active_record/type/hash_lookup_type_map.rb:7>,
   1184=>#<Proc:0x00007fdb0be6d1b8@/*********/vendor/bundle/ruby/2.6.0/gems/activerecord-5.2.4.4/lib/active_record/type/hash_lookup_type_map.rb:7>,
   1186=>#<Proc:0x00007fdb0be6d168@/*********/vendor/bundle/ruby/2.6.0/gems/activerecord-5.2.4.4/lib/active_record/type/hash_lookup_type_map.rb:7>,
   1560=>#<Proc:0x00007fdb0be6d118@/*********/vendor/bundle/ruby/2.6.0/gems/activerecord-5.2.4.4/lib/active_record/type/hash_lookup_type_map.rb:7>,
   1562=>#<Proc:0x00007fdb0be6d0c8@/*********/vendor/bundle/ruby/2.6.0/gems/activerecord-5.2.4.4/lib/active_record/type/hash_lookup_type_map.rb:7>,
   1700=>#<Proc:0x00007fdb0be6d078@/*********/vendor/bundle/ruby/2.6.0/gems/activerecord-5.2.4.4/lib/active_record/type/hash_lookup_type_map.rb:7>,
   2950=>#<Proc:0x00007fdb0be6d028@/*********/vendor/bundle/ruby/2.6.0/gems/activerecord-5.2.4.4/lib/active_record/type/hash_lookup_type_map.rb:7>,
   3614=>#<Proc:0x00007fdb0be6cfd8@/*********/vendor/bundle/ruby/2.6.0/gems/activerecord-5.2.4.4/lib/active_record/type/hash_lookup_type_map.rb:7>,
   3802=>#<Proc:0x00007fdb0be6cf88@/*********/vendor/bundle/ruby/2.6.0/gems/activerecord-5.2.4.4/lib/active_record/type/hash_lookup_type_map.rb:7>,
   13136=>#<Proc:0x00007fdb0be6cc90@/*********/vendor/bundle/ruby/2.6.0/gems/activerecord-5.2.4.4/lib/active_record/type/type_map.rb:32>,
   13139=>#<Proc:0x00007fdb0be6c8d0@/*********/vendor/bundle/ruby/2.6.0/gems/activerecord-5.2.4.4/lib/active_record/type/type_map.rb:32>,
   13141=>#<Proc:0x00007fdb0be6c510@/*********/vendor/bundle/ruby/2.6.0/gems/activerecord-5.2.4.4/lib/active_record/type/type_map.rb:32>,
   13146=>#<Proc:0x00007fdb0be77fa0@/*********/vendor/bundle/ruby/2.6.0/gems/activerecord-5.2.4.4/lib/active_record/type/type_map.rb:32>,
   13148=>#<Proc:0x00007fdb0be77be0@/*********/vendor/bundle/ruby/2.6.0/gems/activerecord-5.2.4.4/lib/active_record/type/type_map.rb:32>,
   143=>#<Proc:0x00007fdb0be77b40@/*********/vendor/bundle/ruby/2.6.0/gems/activerecord-5.2.4.4/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb:97>,
   199=>#<Proc:0x00007fdb0be77aa0@/*********/vendor/bundle/ruby/2.6.0/gems/activerecord-5.2.4.4/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb:97>,
   629=>#<Proc:0x00007fdb0be77a00@/*********/vendor/bundle/ruby/2.6.0/gems/activerecord-5.2.4.4/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb:97>,
   719=>#<Proc:0x00007fdb0be77960@/*********/vendor/bundle/ruby/2.6.0/gems/activerecord-5.2.4.4/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb:97>,
   791=>#<Proc:0x00007fdb0be778c0@/*********/vendor/bundle/ruby/2.6.0/gems/activerecord-5.2.4.4/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb:97>,
   1000=>#<Proc:0x00007fdb0be77820@/*********/vendor/bundle/ruby/2.6.0/gems/activerecord-5.2.4.4/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb:97>,
   1001=>#<Proc:0x00007fdb0be77780@/*********/vendor/bundle/ruby/2.6.0/gems/activerecord-5.2.4.4/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb:97>,
   1002=>#<Proc:0x00007fdb0be776e0@/*********/vendor/bundle/ruby/2.6.0/gems/activerecord-5.2.4.4/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb:97>,
   1003=>#<Proc:0x00007fdb0be77640@/*********/vendor/bundle/ruby/2.6.0/gems/activerecord-5.2.4.4/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb:97>,
   1005=>#<Proc:0x00007fdb0be775a0@/*********/vendor/bundle/ruby/2.6.0/gems/activerecord-5.2.4.4/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb:97>,
   1007=>#<Proc:0x00007fdb0be77500@/*********/vendor/bundle/ruby/2.6.0/gems/activerecord-5.2.4.4/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb:97>,
   1009=>#<Proc:0x00007fdb0be77460@/*********/vendor/bundle/ruby/2.6.0/gems/activerecord-5.2.4.4/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb:97>,
   1028=>#<Proc:0x00007fdb0be773c0@/*********/vendor/bundle/ruby/2.6.0/gems/activerecord-5.2.4.4/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb:97>,
   1014=>#<Proc:0x00007fdb0be77320@/*********/vendor/bundle/ruby/2.6.0/gems/activerecord-5.2.4.4/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb:97>,
   1015=>#<Proc:0x00007fdb0be77280@/*********/vendor/bundle/ruby/2.6.0/gems/activerecord-5.2.4.4/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb:97>,
   1016=>#<Proc:0x00007fdb0be771e0@/*********/vendor/bundle/ruby/2.6.0/gems/activerecord-5.2.4.4/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb:97>,
   1017=>#<Proc:0x00007fdb0be77140@/*********/vendor/bundle/ruby/2.6.0/gems/activerecord-5.2.4.4/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb:97>,
   1018=>#<Proc:0x00007fdb0be770a0@/*********/vendor/bundle/ruby/2.6.0/gems/activerecord-5.2.4.4/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb:97>,
   1019=>#<Proc:0x00007fdb0be77000@/*********/vendor/bundle/ruby/2.6.0/gems/activerecord-5.2.4.4/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb:97>,
   1020=>#<Proc:0x00007fdb0be76f60@/*********/vendor/bundle/ruby/2.6.0/gems/activerecord-5.2.4.4/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb:97>,
   1021=>#<Proc:0x00007fdb0be76ec0@/*********/vendor/bundle/ruby/2.6.0/gems/activerecord-5.2.4.4/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb:97>,
   1022=>#<Proc:0x00007fdb0be76e20@/*********/vendor/bundle/ruby/2.6.0/gems/activerecord-5.2.4.4/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb:97>,
   1027=>#<Proc:0x00007fdb0be76d80@/*********/vendor/bundle/ruby/2.6.0/gems/activerecord-5.2.4.4/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb:97>,
   1040=>#<Proc:0x00007fdb0be76ce0@/*********/vendor/bundle/ruby/2.6.0/gems/activerecord-5.2.4.4/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb:97>,
   1041=>#<Proc:0x00007fdb0be76c40@/*********/vendor/bundle/ruby/2.6.0/gems/activerecord-5.2.4.4/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb:97>,
   651=>#<Proc:0x00007fdb0be76ba0@/*********/vendor/bundle/ruby/2.6.0/gems/activerecord-5.2.4.4/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb:97>,
   1115=>#<Proc:0x00007fdb0be76b00@/*********/vendor/bundle/ruby/2.6.0/gems/activerecord-5.2.4.4/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb:97>,
   1182=>#<Proc:0x00007fdb0be76a60@/*********/vendor/bundle/ruby/2.6.0/gems/activerecord-5.2.4.4/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb:97>,
   1183=>#<Proc:0x00007fdb0be769c0@/*********/vendor/bundle/ruby/2.6.0/gems/activerecord-5.2.4.4/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb:97>,
   1185=>#<Proc:0x00007fdb0be76920@/*********/vendor/bundle/ruby/2.6.0/gems/activerecord-5.2.4.4/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb:97>,
   1187=>#<Proc:0x00007fdb0be76880@/*********/vendor/bundle/ruby/2.6.0/gems/activerecord-5.2.4.4/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb:97>,
   1231=>#<Proc:0x00007fdb0be767e0@/*********/vendor/bundle/ruby/2.6.0/gems/activerecord-5.2.4.4/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb:97>,
   1561=>#<Proc:0x00007fdb0be76740@/*********/vendor/bundle/ruby/2.6.0/gems/activerecord-5.2.4.4/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb:97>,
   1563=>#<Proc:0x00007fdb0be766a0@/*********/vendor/bundle/ruby/2.6.0/gems/activerecord-5.2.4.4/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb:97>,
   2951=>#<Proc:0x00007fdb0be76600@/*********/vendor/bundle/ruby/2.6.0/gems/activerecord-5.2.4.4/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb:97>,
   3643=>#<Proc:0x00007fdb0be76560@/*********/vendor/bundle/ruby/2.6.0/gems/activerecord-5.2.4.4/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb:97>,
   3807=>#<Proc:0x00007fdb0be764c0@/*********/vendor/bundle/ruby/2.6.0/gems/activerecord-5.2.4.4/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb:97>,
   13135=>#<Proc:0x00007fdb0be76420@/*********/vendor/bundle/ruby/2.6.0/gems/activerecord-5.2.4.4/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb:97>,
   13138=>#<Proc:0x00007fdb0be76380@/*********/vendor/bundle/ruby/2.6.0/gems/activerecord-5.2.4.4/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb:97>,
   13140=>#<Proc:0x00007fdb0be762e0@/*********/vendor/bundle/ruby/2.6.0/gems/activerecord-5.2.4.4/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb:97>,
   13145=>#<Proc:0x00007fdb0be76240@/*********/vendor/bundle/ruby/2.6.0/gems/activerecord-5.2.4.4/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb:97>,
   13147=>#<Proc:0x00007fdb0be761a0@/*********/vendor/bundle/ruby/2.6.0/gems/activerecord-5.2.4.4/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb:97>,
   3904=>#<Proc:0x00007fdb0be76100@/*********/vendor/bundle/ruby/2.6.0/gems/activerecord-5.2.4.4/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb:97>,
   3906=>#<Proc:0x00007fdb0be76060@/*********/vendor/bundle/ruby/2.6.0/gems/activerecord-5.2.4.4/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb:97>,
   3908=>#<Proc:0x00007fdb0be75fc0@/*********/vendor/bundle/ruby/2.6.0/gems/activerecord-5.2.4.4/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb:97>,
   3910=>#<Proc:0x00007fdb0be75f20@/*********/vendor/bundle/ruby/2.6.0/gems/activerecord-5.2.4.4/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb:97>,
   3912=>#<Proc:0x00007fdb0be75e80@/*********/vendor/bundle/ruby/2.6.0/gems/activerecord-5.2.4.4/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb:97>,
   3926=>#<Proc:0x00007fdb0be75de0@/*********/vendor/bundle/ruby/2.6.0/gems/activerecord-5.2.4.4/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb:97>,
   22=>#<Proc:0x00007fdb0be75ac0@/*********/vendor/bundle/ruby/2.6.0/gems/activerecord-5.2.4.4/lib/active_record/type/type_map.rb:32>,
   30=>#<Proc:0x00007fdb0be757a0@/*********/vendor/bundle/ruby/2.6.0/gems/activerecord-5.2.4.4/lib/active_record/type/type_map.rb:32>}>

モデルの型定義

モデルの型はテーブル定義情報を基に設定される
https://github.com/rails/rails/blob/main/activerecord/lib/active_record/base.rb

Active Record objects don't specify their attributes directly, but rather infer them from the table definition with which they're linked. Adding, removing, and changing attributes and their type is done directly in the database. Any change is instantly reflected in the Active Record objects. The mapping that binds a given Active Record class to a certain database table will happen automatically in most common cases, but can be overwritten for the uncommon ones.

type_map に設定されている Type::Integer.new(limit: 8) のように、limitを引数にして、Integerクラスのインスタンスが作成される。
上限値を超えてエラーが発生するときは、このクラスで値が範囲外かどうかのチェックをしている。

activemodel-5.2.4.4/lib/active_model/type/integer.rb
def initialize(*)
  super
  @range = min_value...max_value
end

# 継承元のコード抜粋:activemodel-5.2.4.4/lib/active_model/type/value.rb
# initialize_type_map メソッドの Type::Integer.new(limit: 8) で呼び出されるぽい
def initialize(precision: nil, limit: nil, scale: nil)
  @precision = precision
  @scale = scale
  @limit = limit
end

# @rangeの範囲内かを確認している
def ensure_in_range(value)
  unless range.cover?(value)
    raise ActiveModel::RangeError, "#{value} is out of range for #{self.class} with limit #{_limit} bytes"
  end
end

モデルの型はテーブル定義情報を基に設定される為、
以下のように直接テーブル定義情報を変更すると、モデルの型も変更される。

ALTER TABLE public.books ALTER COLUMN id TYPE bigint USING id::bigint;

Discussion