rails: New reference to old table fails on foreign key (MySQL bigint(20) v. int(11))
When creating a new table with a references
column for an existing (pre-5.1) table, the attempt to create a foreign key constraint (in MySQL) fails with a huge backtrace having just a few cryptic clues as to what went wrong.
Steps to reproduce
Create a foreign key to a table created pre-5.1 fails (MySQL). (I know this isn’t an executable test case based on active_record_migrations_gem.rb, but I’m pretty sure this wouldn’t be an issue for SQLite3 anyway.)
In my (client’s) case, the Member
model exists and the Role
and Hat
models are going to be created (for a role-based authorization implementation). Starting simply with:
$ rails g migration CreateRole name description
$ rails g migration CreateHat member:references role:references
Expected behavior
This will create two new tables: a simple roles
table and a simple hats
table that joins Member
to Role
Actual behavior
$ rails db:migrate
== 20170927000118 CreateRole: migrating =======================================
-- create_table(:roles)
-> 0.2327s
== 20170927000118 CreateRole: migrated (0.2331s) ==============================
== 20170927000202 CreateHat: migrating ========================================
-- create_table(:hats)
rails aborted!
StandardError: An error has occurred, all later migrations canceled:
Mysql2::Error: Table 'sa_website4_dev.hats' doesn't exist: SHOW FULL FIELDS FROM `hats`
and many more backtrace lines including these lines:
ActiveRecord::StatementInvalid: Mysql2::Error: Table 'sa_website4_dev.hats' doesn't exist: SHOW FULL FIELDS FROM `hats`
Mysql2::Error: Table 'sa_website4_dev.hats' doesn't exist
Mysql2::Error: Cannot add foreign key constraint
That last one turns out to be the clue!
==> db/migrate/20170927000118_create_role.rb <==
class CreateRole < ActiveRecord::Migration[5.1]
def change
create_table :roles do |t|
t.string :name, index: true, unique: true
t.string :description
end
end
end
==> db/migrate/20170927000202_create_hat.rb <==
class CreateHat < ActiveRecord::Migration[5.1]
def change
create_table :hats do |t|
t.references :member, foreign_key: true
t.references :role, foreign_key: true
end
end
end
When the SQL is generated, the attempt is to make a hats.member_id
which is created as a bigint(20)
be a foreign key referencing members.id
which is a lowly int(11)
having been created from an old migration (before the version tagging began and when 4-byte primary keys were good enough).
The “fix” is to change the migrations to be 5.0 rather than 5.1 and the constraints get created successfully. It would be better to avoid the massive backtrace and give a succinct message or perhaps recognize that the reference requested is to an int(11)
column and create the new column and the constraint accordingly.
System configuration
Rails 5.1.3
ruby 2.3.5p376 (2017-09-14 revision 59905) [x86_64-darwin14]
mysqld Ver 5.7.19 for osx10.10 on x86_64 (Homebrew)
About this issue
- Original URL
- State: closed
- Created 7 years ago
- Reactions: 7
- Comments: 16 (6 by maintainers)
The line
t.references :role, foreign_key: true
is incorrect - it doesn’t correctly reflect the desired behavior. I believe it would work if it specified the type of the reference explicitly:The default for
type
was changed in #26266 but the documentation here didn’t get updated.@dankozlowski there are two different “fixes”. One involves claiming that the migrations are
[5.0]
, but you’re already using Rails 5.0.4 so that can’t be it. The other fix is to specify the:type
of the foreign key as @al2o3cr indicated (and I verified that it worked for me having a new 5.1 join table include a reference to a pre-5.1 table):In my case, the targeted table was actually created in a Rails 4.x system.
How are you encountering this issue in Rails 5.0.4?
I had the same issue, and for any future visitors, it turns out I hadn’t set the
RAILS_ENV
; I have no idea how this solves the problem but it worked for me. None of the other solutions worked.Then a good old reset:
Everything worked like a charm then.
I’m using Rails 5.1.6 and Ruby 2.5.0 on macOS High Sierra.
I’m having this issue as well, and @rab 's fix doesn’t work for me. I’m using Rails 5.0.4.
I’m running into this issue after my migrations started being numbered at
5.1
and it’s really annoying. I can’t have foreign keys right now in my migrations.Getting same error now
rails (7.0.4.3) ruby (3.2.2) mysql (2-0.5.4)
I think the error handling for this has had some weird knock-on effects. We’re getting this error in our migrations, and while we haven’t found a resolution, we’re getting instructions to change to
:integer
even though that’s clearly not the solution.Further details:
Existing Schema
Migration
Error Message
For any foreign key that is a reference to an old table, add
type: :integer
to fix the type to be explicitly integer – int(11), that is – rather than the default:bigint
– aka, bigint(20).