Rails migration for belongs_to association with custom table name

TL;DR: Provide to_table
option like that foreign_key: {to_table: :<table_name>}
.
When it comes to a Rails migration for a belongs_to
association which name doesn’t correspond to the joined table name, it may hard to find out how to do that quickly after reading the Rails documentation or sources. This post should help with that.
Let’s start with the following example:
- there is a
User
model in the system already - we need to add
Payment
model Payment
should belong to areceiver
, that’sUser
.
In the code it would look like that:
class User < ApplicationRecord
end
class Payment < ApplicationRecord
belongs_to :receiver, class_name: 'User'
end
Let’s try to generate a this model and a migration that creates the DB table for it as per the documentation:
rails g model payment receiver:references
That produces the following migration:
class CreatePayments < ActiveRecord::Migration[6.0]
def change
create_table :payments do |t|
t.belongs_to :receiver, null: false, foreign_key: true
t.timestamps
end
end
end
Surprisingly, rake db:migrate
produces the following error:
PG::UndefinedTable: ERROR: relation "receivers" does not exist
And the reason is clear. The migration tries to add a foreign key for a not existing table. It takes the association name receiver
and supposes, as default, that it points to a table that’s plural receivers
. And there is nothing wrong with that. Except the fact, there is no receivers
table and users
table should be used instead.
Unfortunately, after significant time spent on docs reading one may even end up with no solution. It’s hard to spot one line in the examples somewhere in the deep of Rails code. Hence, I provide a solution here:
class CreatePayments < ActiveRecord::Migration[6.0]
def change
create_table :payments do |t|
t.belongs_to :receiver, null: false, foreign_key: {to_table: :users}
t.timestamps
end
end
end
And now the migration runs without any failures and produces a correct result that’s the created payments
table with the receiver_id
column and a foreign key points to the joined users
table.
So, the solution is to use foreign_key: {to_table: :users}
for that example above.
I kindly ask you to participate in the docs improvement. Just vote for this PR. Thank you!
UPDATE 02/20/2020: The PR got merged, what means the documentation got improved!
WideFix and Ruby On Rails expertise
At WideFix, we take pride in our expertise and experience. You can trust that our solutions will not harm your business and will always keep your site running smoothly. You can rely on us to provide confident and effective solutions that meet your needs.