ActiveRecord Relation - da się dodać, odjąć, przefiltrować obiekty itd., ale bez konwersji na tablicę?

Jeśli użyję metody select, to mi zamieni to w tablicę. Ale do tablicy już potem nie mogę dodać zapytania na przykład where.

Obszedłem to tak, że mam tablicę ids z id i potem na końcu dałem

Tag.where(id: ids)

Co daje ActiveRecord Relation. Ale to mi chyba robi dodatkowe zbędne zapytanie do bazy danych.

Powód jest taki, że potrzebuję choćby tym select wybrać tagi, które nie mają rodziców czy dzieci (tag.parents.size == 0, albo tag.parents.empty?).

Poczytaj o joins i includes

Czyli nie ma, i trzeba to robić “hackiem” z łączeniem tabel i dodawaniem warunku, żeby jakaś obojętnie jaka kolumna w obiekcie, którego nie ma, była nil?
Konkretnie w moim przypadku, to wygląda na to, że działa:

Tag.includes(:parent_connections).where(tag_connections: {parent_id: nil})

co jest tym samym co

Tag.includes(:parent_connections).where(tag_connections: {child_id: nil})

Joiny nie są zdecydowanie “hackiem”

Ok. Strasznie zagmatwałeś pytanie, nie jestem wiec pewien o co dokłądnie pytasz, co chcesz osiągnąć.
Spróbuj wrzucić gdzieś na pastie.org schemat tabel (powiązania) i co chcesz osiągnąć właściwie.

Jeżeli chcesz znaleźć tagi które nie mają rodziców to wystarczy:

Tag.where(parent_id: nil)

Jeśli musi to być w jednym zapytaniu to musisz to filtrować bez pomocy active record => bo masz już wszystko w pamięci.

Ja wcale nie przejmowałbym się kolejnym zapytaniem i użył do wszystkiego wcześniej zdefiniowanych w modelu scope’ów. Pseudo:

@all_tags = Tag.any_scope.where(any_condition)

@tags_filtered_1 = @all_tags.additional_filtering_scope if something

# itd...

Chodzi mi o to czy ActiveRecord::Relation można jakoś obrobić, czyli na przykład przeiterować się przez nią i powywalać niepotrzebne rzeczy, ale żeby te wywalone rzeczy nie było kasowane z bazy danych, a tylko traktowane tak, jakby się nigdy nie załapały do tej tablicy (ActiveRecord::Relation to chyba taka ulepszona tablica w sumie?). I dalej mieć ActiveRecord::Relation, a nie zwykłą tablice.

Nie wiem, może jest to zbędne, a ja akurat chciałem zrobić coś skomplikowanego, co i tak dało się załatwić zwykłym includes połączonym z where?

Użycie odpowiedniej kombinacji joins/where, która generuje dobrego SQL-a jest dużo bardziej wydajna, niż rzeźbienie tablicy wyników w Rubym. Jeśli już zaczniesz iterować po ActiveRecord::Relation, to w wyniku dostaniesz tablicę, bo z założenia AR::R możesz chainować z innymi metodami AR i dopóki nie odniesiesz się bezpośrednio do jego elementów, to zapytanie do bazy się nie wykona. Jeśli przefiltrujesz wyniki w Rubym, to nie mógłbyś już dołączać następnych klauzul, bo baza danych by tego nie ogarnęła, dlatego wynikowa kolekcja staje się tablicą. Przy okazji polecam zapoznać się z Arelem, który może posłużyć Ci do napisania dobrych joinów i klazul where.

1 Like