6

Rails3 では、それぞれが異なるインクルードを持つ 2 つのスコープ (ActiveRelations) をチェーンするときに問題があるようです。

次の 2 つのスコープを考えてみましょう。どちらも単独で問題なく動作します。

最初のスコープ:

scope :global_only, lambda { |user|
includes(:country)
.where("countries.area_id <> ?", user.area) }

Work.global_only(user) => (読みやすくするために SQL からフィールドのリストを切り取ります)

SELECT * FROM "works" LEFT OUTER JOIN "countries" ON "countries"."id" = "works"."country_id" WHERE (countries.area_id <> 3)

次に、2 番目のスコープ:

scope :not_belonging_to, lambda { |user| 
includes(:participants)
.where("participants.user_id <> ? or participants.user_id is null", user) }

Work.not_belonging_to(user) => (読みやすさのために SQL からフィールドのリストをカット)

SELECT * FROM "works" LEFT OUTER JOIN "participants" ON "participants"."work_id" = "works"."id" WHERE (participants.user_id <> 6 or participants.user_id is null)

したがって、これらは両方とも個別に適切に機能します。

次に、それらを連鎖させます。

Work.global_only(user).not_belonging_to(user)

SQL:

SELECT (list of fields) FROM "works" LEFT OUTER JOIN "countries" ON "countries"."id" = "works"."country_id" WHERE (participants.user_id <> 6 or participants.user_id is null) AND (countries.area_id <> 3)

ご覧のとおり、2 番目のスコープからの結合は完全に無視されます。したがって、SQL は「no such column 'participants.user_id」で失敗します。スコープを逆の順序でチェーンすると、「参加者」結合が存在し、「国」結合が失われます。失われるのは常に 2 番目の結合です。

これは ActiveRecord のバグのように見えますか、それとも私が何か間違ったことをしているのですか、それともこれは「機能」ですか :-)

(追伸。はい、知っています。両方のテーブルを結合するスコープを作成すると、必要な結果が正しく得られます。それは既にあります。しかし、さまざまな方法でチェーンできるよりも小さなスコープを作成しようとしていました。単純な sql に対する activerecord の利点であると考えられています。)

4

1 に答える 1

5

原則として、:includeseager-loading と:joins条件に使用します。2 番目のスコープでは、左結合が必要なため、結合 SQL を手動で作成する必要があります。

そうは言っても、これを試してください:

scope :global_only, lambda { |user|
  joins(:country).
  where(["countries.area_id != ?", user.area])
}

scope :not_belonging_to, lambda { |user|
  joins("left join participants on participants = #{user.id}").
  where("participants.id is null")
}

Work.global_only(user).not_belonging_to(user)
于 2011-04-05T08:02:52.717 に答える