什么决定 rails 是否在 table 定义中包含 id::serial?
What determines if rails includes id: :serial in a table definition?
我正在使用现有的 rails 应用程序,使用 postgresql。它的 schema.rb 文件有 id: :serial
用于许多但不是全部的表:
create_table "foos", id: :serial, force: :cascade do |t|
当我运行rails db:migrate:reset
时,id: :serial
被移除。我们都使用相同版本的 postgres,但操作系统不同。我没有详尽地测试机器之间的行为,但我认为机器之间存在差异。
rails版本与项目启动时相同
项目确实是从sqlite3开始的。当我切换到那个并重新生成文件时,行为相同。
什么会导致在我的环境中删除此选项?
这里有一些可能相关的代码:
- https://github.com/rails/rails/blob/b2eb1d1c55a59fee1e6c4cba7030d8ceb524267c/activerecord/lib/active_record/connection_adapters/postgresql/column.rb#L15-L21
- https://github.com/rails/rails/blob/b2eb1d1c55a59fee1e6c4cba7030d8ceb524267c/activerecord/lib/active_record/connection_adapters/postgresql/schema_dumper.rb#L26-L42
更新
- 我刚在同事的机器上试过
rails db:migrate:reset
,我错了!他们的环境也删除了 id: :serial
.
- 我仔细查看了一位同事最近的迁移,最近的迁移也没有在 schema.rb 中创建
id: :serial
。
当您 运行 rails db:migrate:reset
而不是 rails db:reset
时,数据库模式不是从 schema.rb
加载的,而是从您的所有迁移中重建的。在迁移和模式文件中,您不需要指定 id
字段,默认情况下会提供一个。但是,从 Rails 5.1 开始,对于 MySQL,default size of the id field was increased 从 INT
到 BIGINT
,对于 PostgreSQL,从 SERIAL
到 BIGSERIAL
.因此,您的迁移 schema.rb
和数据库中的实际模式之间可能存在一些交互,导致 id 字段在某些情况下被视为默认(和省略)并在其他情况下被明确指定,只是由于到默认大小的更改。如果不查看所有相关文件,就很难猜测问题的根源。
答案很简单 rails 5.0 与 5.1 迁移。之前一直以为项目是5.1开始的,所以没测试这个。但后来我深入挖掘,发现它是从 5.0 开始的,实验表明这就是答案。
5.0,未指定 ID
class SerialIdTest < ActiveRecord::Migration[5.0]
def change
create_table "test" do |t|
t.integer "foo_id"
t.string "foo_role"
end
end
end
create_table "test", id: :serial, force: :cascade do |t|
t.integer "foo_id"
t.string "foo_role"
end
# \d test
Table "public.test"
Column | Type | Modifiers
------------------+-------------------+-------------------------------------------------------
id | integer | not null default nextval('test_id_seq'::regclass)
foo_id | integer |
foo_role | character varying |
Indexes:
"test_pkey" PRIMARY KEY, btree (id)
5.1,未指定 ID
class SerialIdTest < ActiveRecord::Migration[5.1]
def change
create_table "test" do |t|
t.integer "foo_id"
t.string "foo_role"
end
end
end
create_table "test", force: :cascade do |t|
t.integer "foo_id"
t.string "foo_role"
end
# \d test
Table "public.test"
Column | Type | Modifiers
------------------+-------------------+-------------------------------------------------------
id | bigint | not null default nextval('test_id_seq'::regclass)
foo_id | integer |
foo_role | character varying |
Indexes:
"test_pkey" PRIMARY KEY, btree (id)
5.1, id serial specified
class SerialIdTest < ActiveRecord::Migration[5.1]
def change
create_table "test", id: :serial do |t|
t.integer "foo_id"
t.string "foo_role"
end
end
end
create_table "test", id: :serial, force: :cascade do |t|
t.integer "foo_id"
t.string "foo_role"
end
# \d test
Table "public.test"
Column | Type | Modifiers
------------------+-------------------+-------------------------------------------------------
id | integer | not null default nextval('test_id_seq'::regclass)
foo_id | integer |
foo_role | character varying |
Indexes:
"test_pkey" PRIMARY KEY, btree (id)
我正在使用现有的 rails 应用程序,使用 postgresql。它的 schema.rb 文件有 id: :serial
用于许多但不是全部的表:
create_table "foos", id: :serial, force: :cascade do |t|
当我运行rails db:migrate:reset
时,id: :serial
被移除。我们都使用相同版本的 postgres,但操作系统不同。我没有详尽地测试机器之间的行为,但我认为机器之间存在差异。
rails版本与项目启动时相同
项目确实是从sqlite3开始的。当我切换到那个并重新生成文件时,行为相同。
什么会导致在我的环境中删除此选项?
这里有一些可能相关的代码:
- https://github.com/rails/rails/blob/b2eb1d1c55a59fee1e6c4cba7030d8ceb524267c/activerecord/lib/active_record/connection_adapters/postgresql/column.rb#L15-L21
- https://github.com/rails/rails/blob/b2eb1d1c55a59fee1e6c4cba7030d8ceb524267c/activerecord/lib/active_record/connection_adapters/postgresql/schema_dumper.rb#L26-L42
更新
- 我刚在同事的机器上试过
rails db:migrate:reset
,我错了!他们的环境也删除了id: :serial
. - 我仔细查看了一位同事最近的迁移,最近的迁移也没有在 schema.rb 中创建
id: :serial
。
当您 运行 rails db:migrate:reset
而不是 rails db:reset
时,数据库模式不是从 schema.rb
加载的,而是从您的所有迁移中重建的。在迁移和模式文件中,您不需要指定 id
字段,默认情况下会提供一个。但是,从 Rails 5.1 开始,对于 MySQL,default size of the id field was increased 从 INT
到 BIGINT
,对于 PostgreSQL,从 SERIAL
到 BIGSERIAL
.因此,您的迁移 schema.rb
和数据库中的实际模式之间可能存在一些交互,导致 id 字段在某些情况下被视为默认(和省略)并在其他情况下被明确指定,只是由于到默认大小的更改。如果不查看所有相关文件,就很难猜测问题的根源。
答案很简单 rails 5.0 与 5.1 迁移。之前一直以为项目是5.1开始的,所以没测试这个。但后来我深入挖掘,发现它是从 5.0 开始的,实验表明这就是答案。
5.0,未指定 ID
class SerialIdTest < ActiveRecord::Migration[5.0]
def change
create_table "test" do |t|
t.integer "foo_id"
t.string "foo_role"
end
end
end
create_table "test", id: :serial, force: :cascade do |t|
t.integer "foo_id"
t.string "foo_role"
end
# \d test
Table "public.test"
Column | Type | Modifiers
------------------+-------------------+-------------------------------------------------------
id | integer | not null default nextval('test_id_seq'::regclass)
foo_id | integer |
foo_role | character varying |
Indexes:
"test_pkey" PRIMARY KEY, btree (id)
5.1,未指定 ID
class SerialIdTest < ActiveRecord::Migration[5.1]
def change
create_table "test" do |t|
t.integer "foo_id"
t.string "foo_role"
end
end
end
create_table "test", force: :cascade do |t|
t.integer "foo_id"
t.string "foo_role"
end
# \d test
Table "public.test"
Column | Type | Modifiers
------------------+-------------------+-------------------------------------------------------
id | bigint | not null default nextval('test_id_seq'::regclass)
foo_id | integer |
foo_role | character varying |
Indexes:
"test_pkey" PRIMARY KEY, btree (id)
5.1, id serial specified
class SerialIdTest < ActiveRecord::Migration[5.1]
def change
create_table "test", id: :serial do |t|
t.integer "foo_id"
t.string "foo_role"
end
end
end
create_table "test", id: :serial, force: :cascade do |t|
t.integer "foo_id"
t.string "foo_role"
end
# \d test
Table "public.test"
Column | Type | Modifiers
------------------+-------------------+-------------------------------------------------------
id | integer | not null default nextval('test_id_seq'::regclass)
foo_id | integer |
foo_role | character varying |
Indexes:
"test_pkey" PRIMARY KEY, btree (id)