У меня проблема с отношением «многие ко многим» с «расширением», порождающим неправильный SQL.
class OrderItem < ApplicationRecord
belongs_to :buyer, class_name: :User
belongs_to :order
belongs_to :item, polymorphic: true
end
class User < ApplicationRecord
has_many :order_items_bought,
-> { joins(:order).where.not(orders: { state: :expired }).order(created_at: :desc) },
foreign_key: :buyer_id,
class_name: :OrderItem
has_many :videos_bought,
-> { joins(:orders).select('DISTINCT ON (videos.id) videos.*').reorder('videos.id DESC') },
through: :order_items_bought,
source: :item,
source_type: :Video do
def confirmed
where(orders: { state: :confirmed })
end
end
end
user.videos_bought.confirmed
генерирует этот SQL:
Video Load (47.0ms) SELECT DISTINCT ON (videos.id) videos.* FROM
"videos" INNER JOIN "order_items" "order_items_videos_join" ON
"order_items_videos_join"."item_id" = "videos"."id" AND
"order_items_videos_join"."item_type" = $1 INNER JOIN
"orders" ON "orders"."id" = "order_items_videos_join"."order_id" INNER JOIN
"order_items" ON "videos"."id" = "order_items"."item_id" WHERE
"order_items"."buyer_id" = $2 AND ("orders"."state" != $3) AND "order_items"."item_type" = $4 AND
"orders"."state" = $5 ORDER BY videos.id DESC, "order_items"."created_at" DESC LIMIT $6
, который возвращает Video
записей, которые объединены с заказами, которые НЕ имеют подтвержденного состояния. Я ожидаю, что все заказы будут подтверждены государством.
Если я использую сырой SQL, все работает нормально:
has_many :videos_bought,
-> {
joins('INNER JOIN orders ON orders.id = order_items.order_id')
.select('DISTINCT ON (videos.id) videos.*')
.reorder('videos.id DESC')
},
through: :order_items_bought,
source: :item,
source_type: :Video do
def confirmed
where(orders: { state: :confirmed })
end
end
Теперь user.videos_bought.confirmed
генерирует этот SQL:
Video Load (5.4ms) SELECT DISTINCT ON (videos.id) videos.* FROM
"videos" INNER JOIN "order_items" ON
"videos"."id" = "order_items"."item_id" INNER JOIN orders ON
orders.id = order_items.order_id WHERE
"order_items"."buyer_id" = $1 AND ("orders"."state" != $2) AND
"order_items"."item_type" = $3 AND "orders"."state" = $4 ORDER BY
videos.id DESC, "order_items"."created_at" DESC LIMIT $5
Что кажется более лаконичным, потому что избегает автоматически сгенерированного order_items_videos_join
имени. Он также возвращает только заказы с подтвержденным состоянием.
Есть идеи, что происходит? Иногда ActiveRecord генерирует ошибочный SQL?
Использование рельсов 5.1.5
. Обновление до последней версии не имеет значения.
Я надеюсь получить объяснение того, почему Rails генерирует строку order_items_videos_join
в первом случае, но не во втором. Кроме того, почему второй запрос SQL дает неверные результаты. При необходимости я могу отредактировать вопрос с помощью большего количества кода и образцов данных.