Активная запись: включает ограничение
У меня есть таблица статей, в которой много изображений
Изображения сортируются для каждой статьи с первым упорядоченным изображением, предназначенным для миниатюры статьи.
В методе индекса контроллера статьи я в настоящее время делаю следующее, чтобы ограничить до 2 активных запросов записи;
@articles = Article.where(:active => true).includes(:images)
И для доступа к миниатюре:
# article model
def thumb
self.images.first if self.images
end
Проблема в том, что это всего 2 запроса, но если в каждой статье есть 10 изображений, и у меня есть 50 статей на каждой странице, тогда я загрузил 500 строк изображения в память.
Есть ли более эффективный способ сделать это в активной записи. Хотел не использовать find_by_sql
Ответы
Ответ 1
2 запроса
@articles = Article.where(:active => true).includes(:thumb)
# app/model/article.rb
has_one :thumb, :class_name => 'Image',
:conditions => { :ordinal => 1 }
1 запрос
Не используйте это решение, если некоторые статьи не имеют большого пальца.
Если вы хотите указать условие для объединенной таблицы, возможно, вы должны использовать joins
вместо includes
:
@articles = Article.joins(:images)
.where(:active => true,
:images => { :ordinal => 1 })
.includes(:images)
Он загружает только изображения, где :ordinal => 1
Я надеюсь, что это поможет
Разница между joins
и includes
при задании условий для активных загруженных ассоциаций:
"Даже несмотря на то, что Active Record позволяет указать условия для загруженных ассоциаций, как и для объединений, рекомендуется использовать вместо этого соединения.
[...]
includes
сгенерируйте запрос, содержащий LEFT OUTER JOIN, тогда как метод joins
будет генерировать один, используя функцию INNER JOIN. "Для дальнейшей помощи см. Раздел" Указание условий в разделе "Заинтересованные загружаемые ассоциации" в "Руководстве по интерфейсу запросов на запись" .
Ответ 2
Это не самый чистый, но вы можете оставить это до двух запросов, выбрав все изображения, связанные с выбранными статьями, которые имеют порядковый номер 1, например:
@articles = Article.where(:active => true).all
images = Image.where(:article_id => @articles.map(&:id), :ordinal => 1).all
Не будет связывать объекты вместе. Вы можете сделать thumb
атрибут доступа, хотя вместо метода, например:
# article model
attr_accessor :thumb
Затем, когда вы загружаете свои изображения, как показано выше, вы можете установить атрибут большого пальца после:
@articles = Article.where(:active => true).all
images = Image.where(:article_id => @articles.map(&:id), :ordinal => 1).all
images_hash = images.each_with_object({}) { |img, h| h[img.article_id] = img }
@articles.each { |article| article.thumb = images_hash[article.id] }
Это один из способов сделать это. ОБНОВЛЕНИЕ: Повышенная эффективность кода выше для предложения @Axsuul в комментариях.
Другим способом, если вы знаете, что каждая статья будет иметь по крайней мере одно изображение, должна появиться со стороны изображений. Выберите все изображения с порядковым номером 1 и включите статьи. Вот так:
@articles = Image.include(:article).where('images.ordinal' => 1, 'articles.active' => true).map(&:article)