JOINS に 3 つ以上のテーブルが含まれる場合、Ruby on Rails で関連付けをどのように処理すればよいですか?

概要

私は Ruby on Rails サーバー (v6.0.1) で作業しており、結合に 3 つのテーブルが含まれる場合に、よりクリーンな ActiveRecord 結合を探しています。状況を説明するために検討中の 5 つのモデルのベアボーン再現をここに示します。

class Person
  # represents a person
end

class Company
  # represents a business entity
  has_many :shifts
end

class Employee
  # represents a person's link with a company.
  belongs_to :person
  belongs_to :company
end

class Shift
  # represents a daily shift that a company has
  belongs_to :company
end

class PersonShift
  # the system maps a person to the shift to indicate they showed up
  belongs_to :person
  belongs_to :shift
  enum status: { ongoing: "ongoing" } # and more
end

従業員ではなく個人を関連付けるシステムの選択により、「現在シフトがアクティブになっている従業員は何名ですか?」という質問に答えるクエリを作成するのが少し難しくなります。単純な SQL に頼ることなく。これは決して問題ではありませんが、ActiveRecord を適切に使用してこの結果を得る方法があるかどうか知りたいです。

今のところ、私にできる最善のことは次のとおりです。

date = Date.today

PersonShift.ongoing.joins(:shift).joins('INNER JOIN employees on employees.company_id = shifts.company_id AND employees.person_id = person_shifts.person_id').where(shifts: { date: }).distinct.select('employees.id')

根本的な問題は、Employee を PersonShift に結合するには Shift と PersonShift を確認する必要があり、単純な結合ではないということです。 has_many スルーのようなものを介して PersonShift と Employee を直接関連付ける方法があればいいのですが?

これはレガシー システムであり、移行には多大な労力が必要になるため、チームはこれを望んでいないため、テーブルを変更することはできません。

解決策

Person と Employee 間の関連付けは 1 対 1 ですか、それとも 1 対多ですか?

1 対 1 の場合、従業員と人の数を数えるのは実際には同じことです。

Person.includes(:person_shifts).where(person_shift: {status: :ongoing, date: Date.today}).count

上記にさらに付け加えます。1 人の人間が同じ日に 2 人の異なる従業員になる可能性はありますか??これら 2 つの異なるテーブルが何を表すかについては詳しく説明されていないので、推測することになります。