Подтвердить что ты не робот

Активная запись: включает ограничение

У меня есть таблица статей, в которой много изображений

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

В методе индекса контроллера статьи я в настоящее время делаю следующее, чтобы ограничить до 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

4b9b3361

Ответ 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)