ActiveRecord: возможно ли создать отношение объединения с областью видимости

#ruby-on-rails #ruby-on-rails-3 #activerecord #rails-activerecord

#ruby-on-rails #ruby-on-rails-3 #activerecord #rails-activerecord

Вопрос:

Вот моя первоначальная проблема. У меня есть две модели, как показано ниже.

 class Author < ActiveRecord::Base
  has_many :books
end
  

и

 class Book < ActiveRecord::Base
  belongs_to :author

  scope :available, ->{ where(available: true) }
end
  

Я хотел бы оставить join Author в области видимости книги «доступным». Ниже приведен запрос, который я хотел бы выполнить в DB. Возможно ли это сделать?

 Select authors.* , count(books.*) as books_count 
From authors left outer join books on books.author_id = authors.id 
and books.available = true 
group by (authors.id) order by books_count;
  

Я попробовал следующий метод

  Author.joins("LEFT OUTER JOIN authors on books.author_id = authors.id")
.merge(Book.available)
.select("authors.* , count(books.*) as books_count")
.group("authors.id").order("books_count")
  

Но это приводит к следующему запросу.

 Select authors.* , count(books.*) as books_count 
From authors left outer join books on books.author_id = authors.id 
where books.available = true 
group by (authors.id) order by books_count;
  

Таким образом, он удаляет всех авторов, у которых нет книги.

Важно: в моей AR-версии нет метода left_outer_joins

Комментарии:

1. Какой результат вы пытаетесь получить?

2. Чтобы найти количество книг каждого автора (есть авторы и без книг) и упорядочить количество книг.

3. @ShanakaKuruwita То есть вы имеете в виду, что в него должны входить авторы, у которых нет книг, но books_count должен быть равен 0. не так ли?

4. @Vishal точно

Ответ №1:

Вам нужно добавить еще один запрос, который проверит, нет ли у автора книг, тогда нам нужно будет добавить его. пожалуйста, попробуйте следующий запрос

  Author.joins("LEFT OUTER JOIN authors on books.author_id = authors.id")
.merge(Book.available)
.where("books.author_id IS NULL")
.select("authors.* , count(books.*) as books_count")
.group("authors.id").order("books_count")
  

Комментарии:

1. это кажется хорошим подходом, но это where добавит оператор AND к предложению where вместо not OR. Итак, я в конечном итоге не получаю результатов. метод ‘или’ недоступен в моей версии.

2. @ShanakaKuruwita or означает, что метод @ShanakaKuruwita недоступен в вашей версии? вы должны использовать OR в запросе. вы пробовали приведенный выше запрос или внесли изменения в свой существующий запрос?

3. да, я попробовал ваш точный запрос. что означало Model.where.или here guides.rubyonrails.org /…

4. @ShanakaKuruwita Но почему вы хотите использовать or метод active record, когда вы можете просто использовать or с приведенным выше запросом. я думаю, что приведенный выше запрос сработает на 100%. вам не нужно искать какие-либо другие активные методы записи

5. Вот запрос, который я получаю:- Выберите authors.* , count(books.*) как books_count От авторов, оставленных для внешнего объединения книг в books.author_id = authors.id где ( books.available = true ) И ( books.author_id РАВНО НУЛЮ ) группируются по (authors.id ) порядок по books_count;

Ответ №2:

Пока оно не использует вашу область видимости. (в основном потому, что ваша область видимости включает предложение where, которое вы не хотите использовать как часть своего запроса)

Вы могли бы сделать это с arel такими:

 book_table = Book.arel_table
author_table = Author.arel_table
author_join = author_table.join(book_table,Arel::Nodes::OuterJoin)
  .on(book_table[:author_id].eq(author_table[:id]).and(
       book_table[:available].eq(true)
    )
  )
Author.joins(author_join.join_sources)
  .select("authors.* , count(books.*) as books_count")
  .group("authors.id").order("books_count")
  

Это приведет к следующему SQL:

 SELECT 
  authors.* , 
  count(books.*) as books_count
FROM 
  authors 
  LEFT OUTER JOIN books ON books.author_id = authors.id
    AND books.available = true
GROUP BY 
  authors.id
ORDER BY 
  books_count
  

Ответ №3:

Если ваше приложение работает на Rails 4.2, то, если вы хотите настоящую поддержку left_outer_joins, просто установите gem «brick», и он автоматически добавит реализацию Rails 5.0 left_outer_joins . Вы, вероятно, захотите отключить остальную часть его функциональности, если только вы не хотите, чтобы в вашем приложении была доступна автоматическая «панель администратора»!