In this step, you will learn how to add a class association to your model code and how to create association links between your seed objects.
We will specifically add the “departure” association between the Airport
and Flight
classes:
As per the diagram:
First, we must add a departure_airport_id
foreign key column to the flights
database table to encode the relationship between each flight and the airport from which it departs.
Generate a partially complete migration script that adds the column by running this rails generate migration
command in the terminal:
rails g migration AddAirportFkColToFlights departure_airport:references
Note that a migration script has been generated with a name similar to db/migrate/20240217224312_add_airport_fk_col_to_flights.rb
(the timestamp will be different).
Specify that the departure_airport_id
foreign keys refer to id
attributes in the airports
database table by updating line 3 in the generated migration as follows using VS Code (especially note the to_table
bit):
add_reference :flights, :departure_airport, null: false, foreign_key: { to_table: :airports }
Reset the database and run the latest migrations by running this command in the terminal:
rails db:migrate:reset
Confirm that the departure_airport_id
column has been added to the flights
table by running this command in the terminal:
psql --command="SELECT * FROM flights" practice_app_development
Note that the departure_airport_id
column is now present in the flights
table
has_many
/belongs_to
declarations to the model classesAdd a has_many
declaration to the Airport
class by editing app/models/airport.rb
in VS Code as follows (comments not shown):
class Airport < ApplicationRecord
has_many(
:departure_flights,
class_name: 'Flight',
foreign_key: 'departure_airport_id',
inverse_of: :departure_airport,
dependent: :destroy
)
end
Here is an explanation of each of the above arguments:
:departure_flights
- The name of a method automatically added to the Airport
class for retrieving all of an airport’s associated departure flights. Because this is a has_many
declaration (emphasis on many), this name is plural.class_name: 'Flight'
- Specifies which type of objects Airport
objects have many of.foreign_key: 'departure_airport_id'
- Specifies the name of the foreign column that encodes this association in the database table. Because this is a has_many
declaration, Rails will automatically infer that the column will be in the database table for the Flight
class.inverse_of: :departure_airport
- Specifies the name of the belongs_to
declaration in the Flight
class that corresponds to this has_many
declaration.dependent: :destroy
- Specifies that, if an Airport
object is deleted, all of its associated Flight
objects should also be deleted automatically. The rational for this is that those flights would no longer make sense without a departure airport.Add a belongs_to
declaration to the Flight
class by editing app/models/flight.rb
in VS Code as follows (comments not shown):
class Flight < ApplicationRecord
belongs_to(
:departure_airport,
class_name: 'Airport',
foreign_key: 'departure_airport_id',
inverse_of: :departure_flights
)
end
Here is an explanation of each of the above arguments:
:departure_airport
- The name of a method automatically added to the Flight
class for retrieving the airport from which a flight departs. Because this is a belongs_to
declaration, this name is singular.class_name: 'Airport'
- Specifies which type of objects Flight
objects belong to.foreign_key: 'departure_airport_id'
- Specifies the name of the foreign column that encodes this association in the database table. Because this is a belongs_to
declaration, Rails will automatically infer that the column will be in the database table for the Flight
class.inverse_of: :departure_flights
- Specifies the name of the has_many
declaration in the Airport
class that corresponds to this belongs_to
declaration.dependent: :destroy
argument here. It is common to delete flights departing from an airport, and deleting such flights should not also cause the airport to be deleted.The belongs_to
declaration automatically adds a validation to the Flight
class such that each Flight
must belong to a corresponding Airport
. If the departure_airport
is set to nil
, a validation error will result. This situation requires us to update our seeds.rb
script, lest running rails db:seed
would result in errors.
Assign each seed Flight
object a departure Airport
object by editing the calls to Flight.create!
in the db/seeds.rb
file as follows using VS Code (note the addition of departure_airport
arguments):
# Flights
mem_atl = Flight.create!(
departure_time: DateTime.strptime('03-02-2028 09:15:00 AM', '%m-%d-%Y %I:%M:%S %p'),
arrival_time: DateTime.strptime('03-02-2028 11:05:00 AM', '%m-%d-%Y %I:%M:%S %p'),
departure_airport: mem
)
mem_lax = Flight.create(
departure_time: DateTime.strptime('01-18-2029 06:42:00 AM', '%m-%d-%Y %I:%M:%S %p'),
arrival_time: DateTime.strptime('01-18-2029 01:16:00 PM', '%m-%d-%Y %I:%M:%S %p'),
departure_airport: mem
)
atl_lax = Flight.create(
departure_time: DateTime.strptime('04-04-2029 10:33:00 AM', '%m-%d-%Y %I:%M:%S %p'),
arrival_time: DateTime.strptime('04-04-2029 05:00:00 PM', '%m-%d-%Y %I:%M:%S %p'),
departure_airport: atl
)
Run the seeds.rb
script by running this command in the terminal:
rails db:seed
As a result of running the seeds.rb
script, the Flight
and Airport
objects should now be configured as follows:
Confirm that the changes made above work correctly by launching the Rails console in the terminal:
rails console
Check that Flight
objects saved in the database have correct values saved in their departure_airport_id
foreign key attributes:
Flight.all
For each Flight
object outputted, note the object’s id
attribute value and its departure_airport_id
attribute value.
The correct values should be as follows:
Flight
with id
of 1 has departure_airport_id
set to 1 (corresponds to MEM airport).Flight
with id
of 2 has departure_airport_id
set to 1 (corresponds to MEM airport).Flight
with id
of 3 has departure_airport_id
set to 2 (corresponds to ATL airport).Confirm that the has_many
declaration works correctly by testing the generated Airport#departure_flights
method. We perform the test on the MEM airport (id
of 1):
Airport.find(1).departure_flights
Note that an array that consists of two Flight
objects (id
values of 1 and 2) is outputted.
Confirm that the belongs_to
declaration works correctly by testing the generated Flight#departure_airport
method. We perform the test on the flight with id
of 1:
Flight.find(1).departure_airport
Note that the MEM Airport
object is outputted.
Exit out of the Rails console to get back to the UNIX prompt:
exit