Rails 按属性值过滤对象数组

因此,我对 db 执行一个查询,就得到了一个完整的对象数组:

@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')

但是在内存中而不是数据库查询中。

125705 次浏览

have you tried eager loading?

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

If your attachments are

@attachments = Job.find(1).attachments

This will be array of attachment objects

Use select method to filter based on file_type.

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

This will not trigger any db query.

Try :

This is fine :

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

but for performance wise you don't need to iterate @attachments twice :

@logos , @images = [], []
@attachments.each do |attachment|
@logos << attachment if attachment.file_type == 'logo'
@images << attachment if attachment.file_type == 'image'
end

You can filter using where

Job.includes(:attachments).where(file_type: ["logo", "image"])

I'd go about this slightly differently. Structure your query to retrieve only what you need and split from there.

So make your query the following:

#                                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"] })

And then partition the data:

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

That will get the data you're after in a neat and efficient manner.

For newer versions of ruby, you can use

@logos = @attachments.filter { |attachment| attachment.file_type == 'logo' }

Reference: https://apidock.com/ruby/Array/filter