Объединение областей не работает
Я пытаюсь объединить три области в одной (одна область использует две другие).
Я хочу получить все видео, которые не имеют определенных категорий и определенных тегов.
видео
class Video < ActiveRecord::Base
self.primary_key = "id"
has_and_belongs_to_many :categories
has_and_belongs_to_many :tags
scope :with_categories, ->(ids) { joins(:categories).where(categories: {id: ids}) }
scope :excluded_tags, -> { joins(:tags).where(tags: {id: 15}) }
scope :without_categories, ->(ids) { where.not(id: excluded_tags.with_categories(ids) ) }
end
Но когда я звоню
@excluded_categories = [15,17,26,32,35,36,37]
@videos = Video.without_categories(@excluded_categories)
Я все еще получаю видео с тегом 15.
Запрос SQL, который запускается сервером, выглядит следующим образом
SELECT "videos"."video_id" FROM "videos" WHERE ("videos"."id" NOT IN (SELECT "videos"."id" FROM "videos" INNER JOIN "tags_videos" ON "tags_videos"."video_id" = "videos"."id" INNER JOIN "tags" ON "tags"."id" = "tags_videos"."tag_id" INNER JOIN "categories_videos" ON "categories_videos"."video_id" = "videos"."id" INNER JOIN "categories" ON "categories"."id" = "categories_videos"."category_id" WHERE "tags"."id" = $1 AND "categories"."id" IN (15, 17, 26, 32, 35, 36, 37))) [["id", 15]]
Я делаю что-то неправильно?
2 ответа
Решение
Я думаю, что вы должны использовать одну область для исключения категорий и вторую для исключения тегов, а затем объединить их.
scope :without_categories, ->(ids) { joins(:categories).where.not(categories: {id: ids}) }
scope :without_tags, ->(ids) { joins(:tags).where.not(tags: {id: ids}) }
Тогда вы можете использовать
@excluded_categories = [1,2,3,4]
@excluded_tags = [1,2,3,4,5,6]
@videos = Video.without_categories(@excluded_categories).without_tags(@excluded_tags)
РЕДАКТИРОВАТЬ после комментария
После просмотра запроса, поскольку связанные области используют AND, созданный запрос не может вернуть желаемый результат. Новый подход будет заключаться в создании одной области только для этой цели.
scope :without_categories_tags, ->
(category_ids, tag_ids) { joins( :categories, :tags).
where('categories.id NOT IN (?) OR tags.id NOT IN (?)', category_ids, tag_ids)}
Вы можете использовать
@excluded_categories = [1,2,3,4]
@excluded_tags = [1,2,3,4,5,6]
@videos = Video.without_categories_tags(@excluded_categories,@excluded_tags)
scope :excluded_tags, -> { joins(:tags).where.not(tags: {id: 15}) }
scope :without_categories, ->(ids) { excluded_tags.with_categories(ids) }