DEV Community

Cover image for Creating a custom name for a foreign key
Joe Avila
Joe Avila

Posted on • Updated on

Creating a custom name for a foreign key

My local basketball league is currently using free software that has shortcomings and is littered with ads. So I'm working on a site where we can upload our game statistics, and is catered to us. It will have more functionality than our current site, no ads, and as a new basketball player I can track my growth. This article is going to dive into creating a customized associations in Rails that will streamline functionality for when I want to display games stats on the frontend.

I have a reference table called games that tracks two teams in my database, the home team and the away team. By keeping this relationship on one table I can make calls to the Game table and find out who the winner was.

rails g resource game home_team:references away_team:references
Enter fullscreen mode Exit fullscreen mode

I'll start by running a generator for games. This will create my model, migration, and controller. I will only focus on the migration and model files as that's where our changes will need to happen. I don't have models called Home Team or Away Team (they are just a Team), so I need to tell Rails what those are and where to look.

Migration

Migration file. Text: class CreateGames < ActiveRecord::Migration[6.0]<br>
  def change<br>
    create_table :games do |t|<br>
      t.references :home_team, null: false, foreign_key: true<br>
      t.references :away_team, null: false, foreign_key: true<br>
      t.references :season, null: false, foreign_key: true<br>
    end<br>
  end<br>
end<br>

In our generated migration file I need to change the ends of line 4 and 5. Here I am telling Rails: these columns are foreign keys of a table with a different name. Home Team and Away Team both point to the Teams table. The new code will be:

class CreateGames < ActiveRecord::Migration[6.0]
  def change
    create_table :games do |t|
      t.references :home_team, null: false, foreign_key: {to_table: :teams}
      t.references :away_team, null: false, foreign_key: {to_table: :teams}
      t.references :season, null: false, foreign_key: true

      t.timestamps
    end
  end
end
Enter fullscreen mode Exit fullscreen mode

Model

Model file. Text: class Game < ApplicationRecord<br>
  belongs_to :season<br>
  belongs_to :home_team<br>
  belongs_to :away_team<br>
end<br>

I need our game model to belong to two teams. This has some conflicts with Active Records base functionality. Inherently belongs_to is a one-to-one connection. I need to change some code here.

class Game < ApplicationRecord
  belongs_to :season
  belongs_to :home_team, class_name: 'Team', foreign_key: 'home_team_id', required: true
  belongs_to :away_team, class_name: 'Team', foreign_key: 'away_team_id', required: true
end
Enter fullscreen mode Exit fullscreen mode

Essentially I am creating an alias. Home Team is actually just a Team, and Away Team is a different Team. This allows me to work around the one-to-one connection of belongs_to while achieving desired functionality.


Voila! I am now able to go into my rails console and create some test data.

hTeam = Team.create(name: "Bears")
aTeam = Team.create(name: "Aces")
g = Game.create(away_team_id: aTeam.id, home_team_id: hTeam.id)

g.home_team
   #=> <Team id: 1, name: "Bears", created_at: "2020-06-01 17:41:14", updated_at: "2020-06-01 17:41:14"> 
g.away_team
   #=> <Team id: 2, name: "Aces", created_at: "2020-06-01 17:42:14", updated_at: "2020-06-01 17:42:14"> 
Enter fullscreen mode Exit fullscreen mode

Top comments (0)