Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What determines if rails includes id: :serial in a table definition?

I'm working with an existing rails app, using postgresql. Its schema.rb file has id: :serial for many, but not all, tables:

create_table "foos", id: :serial, force: :cascade do |t|

When I run rails db:migrate:reset, id: :serial is removed. We are all on the same version of postgres, but different OSes. I haven't exhaustively tested the behavior between machines, but I think there is a difference between machines.

The rails version is the same as it was when the project started.

The project did start with sqlite3. When I switch to that and regenerate the file, same behavior.

What could cause this option to be removed in my environment?

here's some code that is probably relevant:

  • 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

update

  • I just tried rails db:migrate:reset on colleague's machines, and I was wrong! their environments also remove id: :serial.
  • I looked closer at recent migrations from a colleague, and the most recent one did not create id: :serial in schema.rb either.
like image 689
John Bachir Avatar asked Feb 08 '19 18:02

John Bachir


2 Answers

When you run rails db:migrate:reset as opposed to rails db:reset, the database schema is not loaded from schema.rb but is instead reconstructed from all of your migrations. In migrations and schema files you do not need to specify an id field, one is provided by default. However, starting with Rails 5.1, the default size of the id field was increased from INT to BIGINT for MySQL and from SERIAL to BIGSERIAL for PostgreSQL. So probably there is some interaction between your migrations, schema.rb, and the actual schema in the database that is causing the id field to be treated as default (and omitted) in some cases and be explicitly specified in others, just due to the change in the default size. It's hard to guess at the source of the problem without seeing all the relevant files.

like image 186
Old Pro Avatar answered Oct 03 '22 21:10

Old Pro


The answer is simply rails 5.0 vs 5.1 migrations. I had previously thought that the project started in 5.1, so I didin't test this. But then I dug deeper and discovered it started in 5.0, and experimentation shows that's the answer.

5.0, no id specified

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, no id specified

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)
like image 40
John Bachir Avatar answered Oct 03 '22 20:10

John Bachir