Мне нужно отображать только определенные записи из одной таблицы в ActiveAdmin с помощью фильтра, который я реализую как выбор (выпадающий список) и чей код находится в области видимости Rails. У меня проблемы с поиском чистого SQL заменителя в области Rails для следующего условия:
У меня есть следующие модели:
# app/models/score.rb
class Score < ApplicationRecord
has_and_belongs_to_many :export_orders, join_table: :scores_export_orders
end
# app/models/export_order.rb
class ExportOrder < ApplicationRecord
has_and_belongs_to_many :scores, join_table: :scores_export_orders
belongs_to :shop
end
# app/models/shop.rb
class Shop < ApplicationRecord
has_many :export_orders
end
Фильтр позволяет выбрать магазин поэтому относительный код должен возвращать Score::ActiveRecord_Relation
в области видимости.
Условие таково: возвращать все оценки, которые не были экспортированы в выбранный магазин, т.е. все оценки, не имеющие ни одного из них. экспортировать заказы с shop
, равным выбранному магазину .
В качестве примера представьте следующий сценарий:
[608, []]
[607, []]
[606, []]
[593, [nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, 1, 8, 8, 8, nil, nil, nil, nil, 8, 8]]
[586, []]
[585, []]
[372, [nil, nil, 2, nil, nil, nil, 8, 8, 8, nil]]
[157, [nil, 2, nil, nil, nil, 1]]
, где слева у вас есть идентификаторы счета, и справа - массив идентификаторов магазинов их экспортных заказов. Чтобы было понятно, выше приведен результат Score.all.map { |s| [s.id, s.export_orders.map{|o|o.shop_id}] }
.
Так, например, результат Score.not_exported_to(2).ids
должен быть
[608, 607, 606, 593, 586, 585]
, поскольку ни один из порядков экспорта оценок ( с этими идентификаторами) имеет 2
в своих идентификаторах магазинов.
Прямо сейчас, я действительно не могу придумать SQL способ написать это. До сих пор в моей области видимости есть:
# app/models/score.rb
scope :not_exported_to, -> (input) {
shop = Shop.find(input)
export_orders = shop.export_orders
already_exported_score_ids = export_orders.map { |o| o.scores.ids } .flatten.uniq
where.not(id: already_exported_score_ids)
}
Это дает правильный результат, но, очевидно, очень неэффективно, так как использует map
в зависимой ассоциации (Score
), которая выполняет выборку в таблице результатов, повторенную количество раз, равное export_orders.count
. Представьте, что он работает с 1000+ экспортными заказами магазина!
То, что я пробовал до сих пор:
joins("INNER JOIN scores_export_orders ON scores.id = scores_export_orders.score_id INNER JOIN export_orders ON export_orders.id = scores_export_orders.export_order_id").distinct.where("export_orders.shop_id <> #{input}")
, но это возвращает неправильный результат.
Я не очень опытен в SQL, и я боюсь, что мне придется использовать какие-то вложенные запросы, с которыми я не очень знаком.