#ruby-on-rails #views #models
#ruby-on-rails #Вид #Модели
Вопрос:
У меня есть модель под названием websites that has_many :likes
и, конечно, другая модель под названием likes with belongs_to :website
. Я хочу получить массив всех веб-сайтов, но упорядочить их по количеству лайков, которые есть на веб-сайте.
полезная информация:
Я настроил его так, что @website.likes
он будет возвращать лайки с @website
. ( @website.likes.count
— количество лайков на веб-сайте)
Я хочу получить массив всех веб-сайтов, но упорядочить их по количеству лайков, которые есть на веб-сайте.
Комментарии:
1.
sort
не выполняет это с помощью SQL IIRC2. Это может быть приемлемо, если количество сайтов в @popularwebsites невелико. Но если вы сначала соберете все веб-сайты в этот массив, а затем выполните сортировку на лету, это станет дорогостоящим и быстрым. Кроме того, это страдает от так называемой проблемы с запросом N 1, поскольку x.likes.count должен выполнить запрос к базе данных.
Ответ №1:
Как уже писали другие, вы можете выполнить объединение на likes
, а затем упорядочить по количеству. Производительность может быть немного сомнительной в зависимости от индексации и т.д. У вас будет немного другой синтаксис в зависимости от того, используете ли вы Rails 2 или 3.
Альтернативой было бы поддерживать денормализованный likes_count
столбец на websites
, который обновляется при сохранении Like
объекта модели.
Затем вам просто нужно сделать запрос на Website
и указать порядок likes_count
по убыванию (и он легко индексируется).
Для этого создайте likes_count
целочисленный столбец на websites
и укажите :counter_cache
параметр в belongs_to
объявлении в Likes
модели. например:
class Likes
belongs_to :website, :counter_cache => true
end
Проверьте http://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html для получения дополнительной информации
Комментарии:
1. Быстро и просто! Спасибо! (Я так понимаю, что ответ всех остальных тоже сработал!)
2. Классное решение! Недостатком этого является то, что, скажем, если вы удалите лайк из консоли db, удаление не отразится на like_count. В данном случае это не предложение о ставке, но о чем-то, о чем следует знать.
3. @randomguy правильный. Этот метод денормализации основан на создании / уничтожении
Like
объектов, которые должны выполняться с помощью Ruby, и позволяет обратным вызовамActiveRecord
позаботиться о домашнем хозяйстве. Если вы делаете это вне кода своего приложения, то вам нужно выполнить эту уборку самостоятельно, иначе ваши денормализованные данные перейдут в недопустимое состояние.
Ответ №2:
Этот запрос должен дать вам то, что вам нужно:
all(:select => 'websites.*, count(*) as count',
:joins => :likes,
:group => :websites,
:order => 'count DESC')
Комментарии:
1. это не вернет веб-сайты без лайков, потому что внутренние объединения удаляют все веб-сайты, у которых нет лайков, из результирующего набора.
Ответ №3:
Что-то вроде:
SELECT Websites.*, COUNT(Like.ID) AS Liked
FROM websites
LEFT OUTER JOIN Like ON websites.ID = Like.website_id
GROUP BY Like.website_id ORDER BY Liked DESC