Отличный способ научиться — попытаться объяснить, поэтому в процессе изучения ассоциации с рельсами я попытаюсь объяснить несколько более сложную двунаправленную ассоциацию между двумя моделями. Это часть упражнения «Создание продвинутых форм» проекта Odin.

Цель: я хочу создать экспериментальное приложение для бронирования авиабилетов, и первое требование — создать ассоциации между моделью аэропорта и моделью полета.

Шаги:

  1. В каждом аэропорту будет много рейсов, и каждый рейс будет принадлежать аэропорту. Аэропорты имеют 3-буквенные международные коды, например. LIS для международного аэропорта Лиссабона.
  2. Однако для каждого рейса потребуются аэропорты отправления и назначения.
  3. В каждом аэропорту есть вылетающие и прибывающие рейсы.

Так что же это означает для наших модельных ассоциаций?

Шаг 1:

Модель аэропорта имеет переменную Code, которая представляет собой строковое поле, например «SFO» или «LIS». Эта ассоциация создает методы Airport.find(1).flight и Flight.find(1).airport, которые позволяют запрашивать рейсы в аэропорты и аэропорты вылетов соответственно.

Шаг 2:

Теперь нам нужно разделить аэропорты вылета на аэропорты отправления и аэропорты назначения, поскольку рейсы выполняются из пункта А в пункт Б. Мы назовем их from_airport и to_airport, чтобы упростить понимание взаимосвязей. Ассоциации Flight изменены на:

принадлежит_к :из_аэропорта, имя_класса: «Аэропорт»
принадлежит_к :к_аэропорту, имя_класса: «аэропорт»

Это означает, что у каждого рейса будут from_airport и to_airport, но это просто разные экземпляры модели Airport. Это означает, что мы должны создать поле from_airport_id и поле to_airport_id в модели Flight, чтобы связать каждый рейс с двумя аэропортами, пунктом отправления и пунктом назначения.

Шаг 3.

Следующим шагом будет добавление вылетов и прилетов в модель аэропорта. Рейс вылета из аэропорта — это рейс, поле from_airport которого соответствует идентификатору аэропорта этого аэропорта. Прибывающий рейс — это рейс, поле to_airport которого соответствует идентификатору аэропорта.

Итак, что мы хотим сделать, так это назвать эти рейсы «departing_flights» и «arriving_flights» и связать их с полями from_airport_id и to_airport_id в модели Flight. Эта ассоциация выполняется путем установки внешнего_ключа.

has_many :departing_flights, external_key: :from_airport_id, class_name: «Flight»
has_many :arriving_flights, external_key: :to_airport_id, class_name: «Flight»

В описательной форме это означает, что в аэропортах есть рейсы, и они либо отправляются, либо прибывают в зависимости от того, соответствует ли поле from_airport_id или to_airport_id идентификатору аэропорта.

Точно так же у рейсов есть «из аэропортов» (отправление) и «в аэропорты» (пункт назначения), которые задаются идентификаторами в from_airport_id и to_airport_id.

Теперь мы можем использовать такие методы, как Airport.first.departing_flights, чтобы получить вылетающие рейсы из первого аэропорта, и Flight.first.from_airport, чтобы получить пункт отправления первого рейса.

Если бы мы захотели, мы могли бы изменить from_airport на origin и to_airport на вылет, но мы оставим это как есть в интересах простоты. Мы также могли бы добавить inverse_of, чтобы сделать запросы к базе данных более эффективными, но мы также опустим это, поскольку это не является строгим требованием.

И это все. В нашем приложении теперь есть аэропорты со многими вылетающими и прибывающими рейсами, а также рейсы с пунктами отправления и назначения.

— — —

Надеюсь, это было познавательно. Обратная связь всегда приветствуется.