ActiveRecord 結合に追加条件を適用する方法
概要
一定期間における部門ごとの事故数を計算してみようとします。したがって、テーブルが2つあります。 ActiveRecordを使用して答えを取得しようとしていますが、次のようになります
class Division < ApplicationRecord
has_many :accidents
end
class Accident < ApplicationRecord
belongs_to :division
end
Division.left_joins(:accidents).where('accidents.occurred_at > ?', Time.now - 1.year).group(:name).count
この場合、ActiveRecord はこの SQL を生成します
SELECT COUNT(accidents.id) AS "count_all", "divisions"."name" AS "divisions_name"
FROM "divisions"
LEFT OUTER JOIN "accidents" ON "accidents"."division_id" = "divisions"."id"
WHERE (accidents.occurred_at > '2022-07-30 20:56:10.178153')
GROUP BY "divisions"."name"
ここでの問題は、一部の部門の事故数が 0 の場合、クエリ結果に表示されないため、SQL を次のようにする必要があることです。
SELECT COUNT(accidents.id) AS "count_all", "divisions"."name" AS "divisions_name"
FROM "divisions"
LEFT OUTER JOIN "accidents" ON "accidents"."division_id" = "divisions"."id" and accidents.occurred_at > '2022-07-30 20:56:10.178153'
GROUP BY "divisions"."name"
追加の結合条件を指定することはできますか? has_many 関係に追加の条件を指定できることはわかっていますが、それは静的な条件になります。ユーザーのリクエストパラメータに応じて動的にしたい
結合条件 e.q に生の SQL を使用することを避けようとしています。
Division.joins("LEFT OUTER JOIN accidents ON accidents.division_id = divisions.id
and (accidents.occurred_at > '2022-07-30 20:56:10.178153'").group(:name).count('accidents.id')
解決策
最終的なクエリを簡素化するために JOIN でスコープを使用するとどうなるでしょうか?
class Division < ApplicationRecord
scope :with_accidents_from, ->(occurred_at) do
joins_query =
sanitize_sql([
'LEFT OUTER JOIN accidents ON accidents.division_id = divisions.id AND accidents.occurred_at > ?',
occurred_at
])
joins(joins_query)
end
end
その後
Division.with_accidents_from(1.year.ago).group(:name).count('accidents.id')