Рейки, що фільтрують масив об’єктів за значенням атрибута


96

Тому я виконую запит до бази даних і маю повний масив об’єктів:

@attachments = Job.find(1).attachments

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

Щось на зразок цього:

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

Але в пам'яті замість запиту db.


Здається, це хороший варіант використання 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 є майже ідеальним, я просто додам, що у двійкових випадках ви можете використовувати функцію 'partition', щоб зробити речі солодкими. ruby-doc.org/core-1.9.3/Enumerable.html#method-i-partition
Влад

Спасибі @Vlad, це круто, але він підтримує лише в тому випадку, якщо нам потрібно зібрати лише дві речі з об'єкта.
Вік

1
Так, тому я сказав "двійковий" :). У питанні, мабуть, був вибір логотипу чи зображення, тому я додав це для повноти.
Влад

8

Якщо ваші вкладення є

@attachments = Job.find(1).attachments

Це буде масив об’єктів вкладення

Використовуйте метод select для фільтрації на основі типу_файлу.

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

Це не спричинить жодного запиту db.


2

ви пробували нетерпляче завантаження?

@attachments = Job.includes(:attachments).find(1).attachments

На жаль, мені незрозуміло: як фільтрувати за значенням атрибута об’єкта, не перебираючи масив?
joepour

Якщо я правильно зрозумів, вам потрібно менше запитів на базу даних, особливо, коли такий запит, як @attachments = Job.first.attachmentsвиконаний, ви хочете циклізувати @attachmentsтим часом, що більше не хочете запитів на базу даних. це ти хочеш робити?
Siwei Shen 申思维

Я роблю запит db і отримую масив об’єктів. Потім я хочу створити два окремі списки з цього одного масиву, фільтруючи об’єкти на основі значення їх атрибутів (Див. Оригінальний пост) - ура
joepour


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" }

Це дозволить отримати дані, за якими ви шукаєте, акуратно та ефективно.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.