Foreign Keys in Ruby on Rails
3 min read
A foreign key is an important tool in the world of databases. What it is, is alluded to in the name: a key is how you gain access to something, while foreign means from another place.
To understand how foreign keys are used in Rails, we need to know a little about models, databases, and migrations too. To better illustrate the use of foreign keys and these other concepts, we’ll board the USS Enterprise.
USS Enterprise example
You are an ensign within the engineering department of the USS Enterprise. You have a list of tasks displayed on your PADD (personal access display device) that you need to complete.
Your first task today is to complete maintenance of the warp drive, and it was ordered by Chief Engineer Geordi La Forge. When Geordi first added this task it saves to a database (like an excel spreadsheet). Your PADD retrieves information from that database in order to display the tasks Geordi added.
The database is organized into tables, which is like having an excel spreadsheet broken up into categories. For example, the list of tasks you need to complete are in the tasks table. This organization is key to speedy data access, because rather than the computer searching through mountains of data (medical records, officer profiles, mission notes, etc, etc) to find one item (a task) it can just look through the tasks table.
But with this separation, the tables need a way to tap into each other in some instances. For example, the task maintenance of warp drive in the tasks table needs to be associated with an officer(you the ensign) in the officers table.
In one file here’s how you associate the officers table with the tasks table:
class Officer < ActiveRecord::Base
has_many :tasks
end
And in another file here’s how you can associate tasks with the officers table:
class Task < ActiveRecord::Base
belongs_to :officers
end
Breaking it Down:
class Officer < ActiveRecord::Base
class Task < ActiveRecord::Base
These lines of code create what is called a model class in Ruby. In this example, we are creating the Officer model to chat with the officers table and the Task model to chat with the tasks table.
Models are like the guardians of the database. They tell their data what it’s allowed to do, decides which data is valid for their table, who their data can chat with and in what way, and how the data can be manipulated.
has_many :tasks
belongs_to :officers
These lines of code describe the association(relationship) between the two tables. It states a single officer can have many tasks, and a task belongs to a single officer.
Now that the Officer model and the Task model are associated with each other, we need attributes. An attribute describes the type of data we are entering into the table. For example, for the Officer table we need the attributes id, officer’s name, and their rank. For the Task table we need id, officer’s id, and task. The id is a way for Rails to locate the data needed, and is automatically generated when you create the model.
Luckily, with Ruby on Rails when you create a model (like the Officer and Task models) you automatically create migration files containing the attributes. Migrations are a less time-consuming and easier way to alter your database schema (structure of the database) than having to write SQL(database language) by hand.
This is how to create the Officer and Task models mentioned above within the terminal:
rails generate model Officer name:text rank:text
rails generate model Task task:text officer_id:integer
And here is the code that’s generated in the task and officer migration files:
class CreateTasks < ActiveRecord::Migration
def change
create_table :tasks do |t|
t.integer :id
t.integer :officer_id
t.text :task
end
end
end
class CreateTasks < ActiveRecord::Migration
def change
create_table :tasks do |t|
t.integer :id
t.integer :officer_id
t.text :task
end
end
end