Как выполнять соединения для подзапросов в AREL в Rails

у меня простая модель

class User
    has_many :logs


class Logs

связаны обычным образом через внешний ключ logs.user_id. Я пытаюсь сделать следующее, используя Arel, и, согласно документу Arel, это должно работать.

u_t = Arel::Table::new :users
l_t = Arel::Table::new :logs

counts = l_t.
    group(l_t[:user_id]).
    project(
        l_t[:user_id].as("user_id"),
        l_t[:user_id].count.as("count_all")
    )

l_t.joins(counts).on(l_t[:id].eq(counts[:user_id]))

Когда я это делаю, я получаю ошибку

TypeError: Cannot visit Arel::SelectManager

Однако автор Arel недвусмысленно предполагает, что Arel может делать такие вещи.

Пожалуйста, не пишите ответы о том, как я могу выполнить тот же запрос с помощью необработанного sql, другого типа запроса Arel и т. д. Меня интересует шаблон, а не конкретные результаты этого запроса.


person bradgonesurfing    schedule 23.09.2011    source источник


Ответы (2)


Вы можете использовать join_sources для получения Arel::Nodes::Join из экземпляра Arel::SelectManager и передать его в соединения.

Используя ваш пример:

l_t.joins(counts.join_sources).on(l_t[:id].eq(counts[:user_id]))
person rfb    schedule 01.03.2012
comment
l_t[:id].eq(counts[:user_id]) это работает? Я имею в виду, почему идентификатор журнала должен быть равен идентификатору пользователя? - person Alexander; 03.07.2017

Это обеспечивает соединение вложенного подзапроса select с Arel:

Вы можете добавить вложенную область inner_query и external_query в свой файл модели и использовать...

  inner_query = Model.inner_query(params)
  result = Model.outer_query(params).joins(Arel.sql("(#{inner_query.to_sql})"))
   .group("...")
   .order("...")

Для вариантов этого, например, для использования INNER JOIN в подзапросе, сделайте следующее:

  inner_query = Model.inner_query(params)
  result = Model.outer_query(params).joins(Arel.sql("INNER JOIN (#{inner_query.to_sql}) tablealias ON a.id = b.id"))
   .group("...")
   .order("...")

Добавьте определенные объединения, ограничения и группировки в каждую из областей запросов, чтобы дополнительно изменить оператор sql, т.е.:

scope :inner_query , -> (company_id, name) {
    select("...")
    .joins("left join table1 on table1.id = table2.id")
    .where("table1.company_id = ? and table1.name in (?)", company_id, name)
    .group("...")
}

Это позволяет вам помещать условия WHERE во вложенный запрос, а также во внешний запрос.

person aabiro    schedule 14.02.2019