Multiple foreign keys for the same model in Rails 6

Lucas Hiago
3 min readJun 14, 2020

--

It’s quite easy to create tables with Ruby On Rails, but some cases require a little personalization to reproduce real world situations and the relationships between them. Here, we have two models: User and Meeting. They have a 1..N relation, so one User will be part of a meeting and a Meeting will have two users (yes, specifically two). The problem doesn’t rely on this relationship but in the generated migration because we cannot have two t.references :user_id and we also want to identify which user is available for the meeting and which user who requested the meeting.

Before we start with the solution, let’s understand the commandrails generate or the shorthand coderails g .

This command is one of the many options that follow therails command. If you open your terminal and run rails --help , you’ll see a list of options:

$ rails --helpThe most common rails commands are:
generate Generate new code (short-cut alias: "g")
console Start the Rails console (short-cut alias: "c")
server Start the Rails server (short-cut alias: "s")
test Run tests except system tests (short-cut alias: "t")
test:system Run system tests
dbconsole Start a console for the database specified in config/database.yml (short-cut alias: "db")
new Create a new Rails application. "rails new my_app" creates a new application called MyApp in "./my_app"

And if we run rails generate --help another list of options will be shown:

$ rails g --help                                
Spring preloader in process 70748
Usage: rails generate GENERATOR [args] [options]
...
Please choose a generator below.
Rails:
application_record
assets
channel
controller
generator
helper
integration_test
jbuilder
job
mailbox
mailer
migration
model
resource
responders_controller
scaffold
scaffold_controller
system_test
task
...

In this article, we will use the rails db:migrate and rails generate model options to create our models and save them on db/schema.rb , the file that represents our database.

First, we will generate the model User and Meeting

$ rails generate model User name:string email:string

$ rails generate model Meeting starts_at:datetime ends_at:datetime available_user:references requester_user:references

They will generate the migration files, the model files under app/models , and the test files. Meeting’s migration should look like this:

Migration to create the table Meeting on database

But if you try to run rails db:migrate to create the tables in the database an error will be raised on your terminal since there aren’t tables called available_user and requester_user to make reference as Foreign Key. With that in mind, our next step is to remove the foreign_key: true , create the foreign key reference with the correct columns, and then the file should look like this:

Now we can safely run rails db:migrate and see the changes in db/schema.rb .

In order to tell Rails what table will be referenced by the Meetings model, we should make changes on our model files app/models/meetings.rb and app/models/users.rb . They should look like this:

Now the relationship is done and we can create meetings and users in this way:

user1 = User.create!(name: 'John Snow', email: 'night_watcher@thegreatwall.com')
=> #<User id: 1, name: "John Snow", email: "night_watcher@thegreatwall.com", created_at: "2020-06-12 20:34:41", updated_at: "2020-06-12 20:34:41">
user2 = User.create!(name: 'Daenerys Targaryen', email: 'stormborn@dragonstone.com')
=> #<User id: 2, name: "Daenerys Targaryen", email: "stormborn@dragonstone.com", created_at: "2020-06-12 20:36:10", updated_at: "2020-06-12 20:36:10">

starting_time = Time.zone.now
ending_time = Time.zone.now + 2.hour
meeting_about_family = Meeting.create!(starts_at: starting_time, ends_at: ending_time, available_user_id: user2.id, requester_user_id: user1.id)
=> #<Meeting id: 1, starts_at: "2020-06-12 20:40:45", ends_at: "2020-06-12 22:41:04", available_user_id: 2, requester_user_id: 1, created_at: "2020-06-12 20:41:41", updated_at: "2020-06-12 20:41:41">

meeting_about_family.available_user
=> #<User id: 2, name: "Daenerys Targaryen", email: "stormborn@dragonstone.com", created_at: "2020-06-12 20:36:10", updated_at: "2020-06-12 20:36:10">
meeting_about_family.requester_user
=> #<User id: 1, name: "John Snow", email: "night_watcher@thegreatwall.com", created_at: "2020-06-12 20:34:41", updated_at: "2020-06-12 20:34:41">

--

--