In rails, to add a foreign key, we usually do
rails generate migration AddReferenceToXX mm:references
what this does is that it adds a foreign key to the XX table, and uses the mm model's attribute id as the referenced column. However, this id is not what we'd always want to use as a foreign key, what if we want to use some other column as a foreign key, let's say the column email? In this article, we're going to learn exactly that thing.
Suppose we have two models named GmailInbox and GmailThread, their relationship being that GmailInbox has many GmailThreads and a GmailThread belongs to only one GmailInbox, so it's a One-to-Many relationship.
We need a way to connect the GmailThread to a GmailInbox based on the email (because a Gmail account is identified based on the email)
GmailInbox: id, email
where email attribute will have a uniqueness constraint (i.e no duplicates allowed in this column since it is going to be a referenced column for a foreign key).
GmailThread: id, thread_id, inbox_email
we will use inbox_email attribute as a foreign key to refer to the Gmail inbox it belongs to.
Firstly, we will generate a migration, using
rails generate migration add_foreign_key_to_gmail_threads
Then we need to add uniqueness constraint on the column of the referenced table, after that, we'll add the foreign key to the gmail_threads table.
our migration file will be
def change
add_index :gmail_inboxes, :email, unique: true
add_foreign_key :gmail_threads, :gmail_inboxes, column: :inbox_email, primary_key: :email
end
the syntax explanation is
add_index :table_name, :column_name, unique: true
add_foreign_key :from_table, :to_table, column: :foreign_key_column, primary_key: :referenced_column
The last thing we need to do is to put the foreign key information in our models.
class GmailThread < ApplicationRecord
belongs_to :gmail_inbox, foreign_key: 'inbox_email', primary_key: 'email', optional: true
end
and do the same in GmailInbox model
class GmailInbox < ApplicationRecord
has_many :gmail_threads, foreign_key: 'inbox_email', primary_key: 'email'
end
and that's it.
Top comments (2)
Really appreciated the breakdown, thanks.
glad that it helped!