проблема: activerecord (rails3), связывание областей с включениями - PullRequest
6 голосов
/ 03 августа 2010

В Rails3, по-видимому, возникает проблема при объединении двух областей (ActiveRelations), каждая из которых имеет разные значения:

Рассмотрим эти две области видимости, обе прекрасно работают самостоятельно:

Первая сфера:

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)

Теперь вторая область:

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

Work.not_belonging_to (пользователь) => (вырезать список полей из 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 (пользователь) .not_belonging_to (пользователь)

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)

Как видите, объединение из второй области полностью игнорируется. Таким образом, SQL завершается ошибкой на «нет такого столбца» members.user_id ». Если я поставлю цепочку областей в обратном порядке, то будет присутствовать объединение «участники» и объединение «страны» будет потеряно. Кажется, всегда теряется второе соединение.

Похоже ли это на ошибку в ActiveRecord, или я делаю что-то не так, или это "особенность" :-)

(PS. Да, я знаю, я могу создать область, объединяющую обе таблицы, и она будет правильно давать желаемый результат. У меня это уже есть. Но я пытался создать области меньшего размера, чем можно связать вместе в разных пути, который должен быть преимуществом activerecord над прямой sql.)

1 Ответ

5 голосов
/ 05 апреля 2011

Как правило, используйте :includes для быстрой загрузки и :joins для условий. Во второй области 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)
...