私はこれらの2つのモデルを持っています:
Collabs
- id
- title
# has_many :collaborations
Collaborations
- collab_id
- user_id
- status
# belongs_to :collab
# belong_to :user
クエリでは、特定のuser_idが子(コラボレーション)の関連付けに存在しないすべてのコラボレーションをフェッチする必要はありません。コラボレーションには0から多数のコラボレーションを含めることができ、コラボレーションには異なるuser_idがあります。
私は(スコープを使用して)試しました:
collabs = Collab.available_for_user(2)
scope :available_for_user, -> (user_id) { joins(:collaborations).where.not(collaborations: {user_id: user_id}) }
私も試しました:
scope :available_for_user, -> (user_id) { left_outer_joins(:collaborations).where.not(collaborations: {user_id: user_id}) }
これは、コンソールに出力されるSQLです。
SELECT "collabs".* FROM "collabs" LEFT OUTER JOIN "collaborations" ON "collaborations"."collab_id" = "collabs"."id" WHERE ("collaborations"."user_id" != $1) [["user_id", 13]]
これは、子アソシエーションに指定されたuser_idのみがあり、コラボに別のuser_idとの別のコラボレーションがある場合に機能し、このコラボは上記のスコープでフェッチされます。
これはあなたの呼び出しです:
Collab.find_by_sql [
"SELECT *
FROM collabs
WHERE id NOT IN (
SELECT C.id
FROM collabs C
JOIN collaborations CL ON CL.collab_id = C.id
WHERE CL.user_id = :user_id)",
{ user_id: user_id }
]
説明:選択したuser_idのコラボレーションがないコラボをフェッチするには、そのコラボがあるコラボを見つけて除外する必要があります。:)
SQLがなく、プレーンなRubyを使用すると、次のように記述できます。
Collab.where.not(
id: Collab.joins(:collaborations)
.where(collaborations: { user_id: user_id })
.pluck(:id)
)
または、詳細:
# Inner query to find collabs with collaborations for given user_id:
# SELECT C.id
# FROM collabs C
# JOIN collaborations CL ON CL.collab_id = C.id
# WHERE CL.user_id = :user_id
ids = Collab.joins(:collaborations)
.where(collaborations: { user_id: user_id })
.pluck(:id)
# Final query:
# SELECT *
# FROM collabs
# WHERE id NOT IN :ids
Collab.where.not(id: ids)
最初のケース(find_by_sql)では1つではなく2つのSQL呼び出しが生成されるため、パフォーマンスのためにそうしないでください。
この記事はインターネットから収集されたものであり、転載の際にはソースを示してください。
侵害の場合は、連絡してください[email protected]
コメントを追加