Rails фильтрует массив объектов по значению атрибута

96

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

@attachments = Job.find(1).attachments

Теперь, когда у меня есть массив объектов, я не хочу выполнять другой запрос к базе данных, но я хотел бы отфильтровать массив на основе Attachmentобъекта, file_typeчтобы у меня был список того, attachmentsгде находится тип файла, 'logo'а затем другой список того, attachmentsгде тип файла'image'

Что-то вроде этого:

@logos  = @attachments.where("file_type = ?", 'logo')
@images = @attachments.where("file_type = ?", 'image')

Но в памяти вместо запроса к БД.

Joepour
источник
Похоже на хороший вариант использования partition- например, здесь .
SRack

Ответы:

172

Пытаться :

Это отлично :

@logos = @attachments.select { |attachment| attachment.file_type == 'logo' }
@images = @attachments.select { |attachment| attachment.file_type == 'image' }

но для повышения производительности вам не нужно дважды повторять @attachments:

@logos , @images = [], []
@attachments.each do |attachment|
  @logos << attachment if attachment.file_type == 'logo'
  @images << attachment if attachment.file_type == 'image'
end
Вик
источник
2
Поскольку решение @ Vik в значительной степени идеальное, я просто добавлю, что в двоичных случаях вы можете использовать функцию «разбиения», чтобы сделать вещи приятными. ruby-doc.org/core-1.9.3/Enumerable.html#method-i-partition
Влад
Спасибо @Vlad, это круто, но он поддерживает, только если нам нужно собрать только две вещи из объекта.
Вик
1
Да, поэтому я сказал "двоичный" :). В вопросе, по-видимому, был выбор логотипа или изображения, поэтому я добавил это для полноты.
Влад
8

Если ваши вложения

@attachments = Job.find(1).attachments

Это будет массив объектов прикрепления

Используйте метод выбора для фильтрации на основе file_type.

@logos = @attachments.select { |attachment| attachment.file_type == 'logo' }
@images = @attachments.select { |attachment| attachment.file_type == 'image' }

Это не вызовет никаких запросов к базе данных.

Саундар Ратинасами
источник
2

вы пробовали активную загрузку?

@attachments = Job.includes(:attachments).find(1).attachments
Сивэй Шэнь 申思维
источник
Извините, я не совсем понимаю: как мне фильтровать по значению атрибута объекта, не просматривая массив?
joepour
Если я правильно понял, вам нужно меньше запросов к базе данных, особенно после того, как запрос, например, @attachments = Job.first.attachmentsвыполнен, вы хотите зациклить, @attachmentsпока вы не хотите больше запросов к базе данных. это то, что ты хочешь сделать?
Siwei Shen 申思维
Я делаю запрос к базе данных и получаю массив объектов. Затем я хочу создать два отдельных списка из этого одного массива, отфильтровав объекты по значению их атрибутов (см. Исходный пост) - ура
joepour
0

Вы можете фильтровать, используя где

Job.includes(:attachments).where(file_type: ["logo", "image"])
Дарлан Д.
источник
0

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

Итак, сделайте свой запрос следующим образом:

#                                vv or Job.find(1) vv
attachments = Attachment.where(job_id: @job.id, file_type: ["logo", "image"])
# or 
Job.includes(:attachments).where(id: your_job_id, attachments: { file_type: ["logo", "image"] })

А затем разделите данные:

@logos, @images = attachments.partition { |attachment| attachment.file_type == "logo" }

Это позволит получить нужные вам данные аккуратно и эффективно.

SRack
источник