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