Railsy filtrują tablicę obiektów według wartości atrybutu

96

Więc wykonuję zapytanie do bazy danych i mam pełną tablicę obiektów:

@attachments = Job.find(1).attachments

Teraz, gdy mam tablicę obiektów, nie chcę wykonywać kolejnego zapytania db, ale chciałbym przefiltrować tablicę na podstawie Attachmentobiektu, file_typeaby mieć listę miejsc, w attachmentsktórych znajduje się typ pliku, 'logo'a następnie kolejną listę attachmentsmiejsc typ pliku to'image'

Coś takiego:

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

Ale w pamięci zamiast zapytania db.

joepour
źródło
Wydaje się, że jest to dobry przypadek użycia partition- na przykład tutaj .
SRack

Odpowiedzi:

172

Próbować :

Jest okej :

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

ale ze względu na wydajność nie musisz dwukrotnie iterować @ załączników:

@logos , @images = [], []
@attachments.each do |attachment|
  @logos << attachment if attachment.file_type == 'logo'
  @images << attachment if attachment.file_type == 'image'
end
Vik
źródło
2
Ponieważ rozwiązanie @ Vika jest prawie idealne, dodam tylko, że w przypadkach binarnych można użyć funkcji „partycji”, aby uczynić wszystko słodkim. ruby-doc.org/core-1.9.3/Enumerable.html#method-i-partition
Vlad,
Dzięki @Vlad, to super, ale obsługuje tylko wtedy, gdy musimy zebrać tylko dwie rzeczy z obiektu.
Vik
1
Tak, dlatego powiedziałem „binarne” :). W pytaniu najwyraźniej był wybór logo lub obrazu, więc dodałem to dla kompletności.
Vlad
8

Jeśli twoje przywiązania są

@attachments = Job.find(1).attachments

Będzie to tablica obiektów załączników

Użyj metody select, aby filtrować na podstawie file_type.

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

Nie spowoduje to żadnego zapytania o bazę danych.

Soundar Rathinasamy
źródło
2

czy próbowałeś chętnego ładowania?

@attachments = Job.includes(:attachments).find(1).attachments
Siwei Shen 申思维
źródło
Przepraszam, nie jestem jasny: jak filtrować według wartości atrybutu obiektu bez zapętlania tablicy?
joepour
Jeśli dobrze zrozumiałem, chcesz mniej zapytań db, zwłaszcza po wykonaniu zapytania, takiego jak zapytanie @attachments = Job.first.attachments, chcesz zapętlić, a @attachmentstymczasem nie chcesz więcej zapytań db. czy to jest to, co chcesz zrobić?
Siwei Shen 申思维
Robię zapytanie o bazę danych i otrzymuję tablicę obiektów. Następnie chcę utworzyć dwie oddzielne listy z tej jednej tablicy, filtrując obiekty na podstawie wartości ich atrybutów (Zobacz oryginalny post)
Pozdrawiam
0

Możesz filtrować za pomocą gdzie

Job.includes(:attachments).where(file_type: ["logo", "image"])
Darlan D.
źródło
0

Podszedłbym do tego nieco inaczej. Skonfiguruj zapytanie tak, aby pobierało tylko to, czego potrzebujesz, i dziel je stamtąd.

Więc stwórz następujące zapytanie:

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

A następnie podziel dane:

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

Pozwoli to uzyskać potrzebne dane w schludny i wydajny sposób.

SRack
źródło