Rails che filtra l'array di oggetti in base al valore dell'attributo


96

Quindi eseguo una query al db e ho un array completo di oggetti:

@attachments = Job.find(1).attachments

Ora che ho un array di oggetti non voglio eseguire un'altra query db, ma vorrei filtrare l'array in base Attachmentall'oggetto in file_typemodo da poter avere un elenco di attachmentsdove si trova il tipo di file'logo' e poi un altro elenco di attachmentsdove il tipo di file è'image'

Qualcosa come questo:

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

Ma in memoria invece di una query db.


Sembra un buon caso d'uso per partition- ad esempio qui .
SRack

Risposte:


172

Provare :

Questo va bene :

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

ma per quanto riguarda le prestazioni non è necessario ripetere due volte gli allegati @:

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

2
Poiché la soluzione di @ Vik è praticamente ideale, aggiungerò solo che nei casi binari, potresti usare una funzione di "partizione" per rendere le cose dolci. ruby-doc.org/core-1.9.3/Enumerable.html#method-i-partition
Vlad

Grazie @Vlad, è fantastico, ma supporta solo se dobbiamo raccogliere solo due cose dall'oggetto.
Vik

1
Sì, è per questo che ho detto "binario" :). Nella domanda apparentemente c'era una scelta di logo o immagine, quindi l'ho aggiunta per completezza.
Vlad

8

Se i tuoi allegati sono

@attachments = Job.find(1).attachments

Questo sarà un array di oggetti allegati

Usa il metodo di selezione per filtrare in base a file_type.

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

Ciò non attiverà alcuna query db.


2

hai provato a caricare con entusiasmo?

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

Scusa, non sono chiaro: come faccio a filtrare in base al valore dell'attributo di un oggetto senza scorrere l'array?
joepour

Se ho capito bene, vuoi meno query db, soprattutto, una volta @attachments = Job.first.attachmentseseguita una query come eseguita, vuoi eseguire il ciclo nel @attachmentsfrattempo non vuoi più query db. è questo quello che vuoi fare?
Siwei Shen 申思维

Eseguo una query db e ricevo un array di oggetti. Quindi voglio creare due elenchi separati da
quell'un

0

Puoi filtrare usando dove

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

0

Lo farei in modo leggermente diverso. Struttura la tua query per recuperare solo ciò di cui hai bisogno e dividerla da lì.

Quindi fai la tua query come segue:

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

Quindi partizionare i dati:

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

Otterrai i dati che stai cercando in modo pulito ed efficiente.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.