私は 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 つの異なるテーブルが何を表すかについては詳しく説明されていないので、推測することになります。