Załóżmy, że mam następujące dwa obiekty:
first_name_relation = User.where(:first_name => 'Tobias') # ActiveRecord::Relation
last_name_relation = User.where(:last_name => 'Fünke') # ActiveRecord::Relation
czy można połączyć te dwie relacje w celu uzyskania jednego ActiveRecord::Relation
obiektu zawierającego oba warunki?
Uwaga: zdaję sobie sprawę, że mogę połączyć miejsca, aby uzyskać takie zachowanie, naprawdę interesuje mnie przypadek, w którym mam dwa oddzielne ActiveRecord::Relation
obiekty.
ruby-on-rails
rails-activerecord
arel
Patrick Klingemann
źródło
źródło
Odpowiedzi:
Jeśli chcesz połączyć używając
AND
(przecięcie), użyjmerge
:Jeśli chcesz połączyć za pomocą
OR
(union), użyj † :or
† Tylko w ActiveRecord 5+; dla 4.2 zainstaluj gdzie-lub backport.
źródło
ActiveRecord::Relation
typem?merge
jest to skrzyżowanie, a nie związek.#or
metoda została dodana do ActiveRecord :: Relation w styczniu 2015 r. I będzie częścią Rails 5.0 , która zostanie udostępniona pod koniec 2015 r. Pozwala na użycie operatora OR do łączenia klauzul WHERE lub HAVING. Możesz kupić HEAD, jeśli potrzebujesz go przed oficjalną premierą. Zobacz Merge Pull Request # 16052 @Arcolye @AndrewMarshall @ Aldo-xoen-GiambellucaObiekty relacji można konwertować na tablice. To neguje możliwość późniejszego użycia na nich jakichkolwiek metod ActiveRecord, ale nie musiałem. Ja to zrobiłem:
Ruby 1.9, szyny 3.2
źródło
merge
właściwie nie działa jakOR
. To po prostu przecięcie (AND
)Zmagałem się z tym problemem, aby połączyć obiekty ActiveRecord :: Relation w jeden i nie znalazłem dla mnie działającego rozwiązania.
Zamiast szukać właściwej metody tworzenia unii z tych dwóch zbiorów, skupiłem się na algebrze zbiorów. Możesz to zrobić w inny sposób, korzystając z prawa De Morgana
ActiveRecord zapewnia metodę scalania (AND), a także możesz użyć not method lub none_of (NOT).
Masz tutaj (A u B) '= A' ^ B '
AKTUALIZACJA: powyższe rozwiązanie jest dobre w bardziej złożonych przypadkach. W twoim przypadku coś takiego wystarczy:
źródło
Udało mi się to osiągnąć, nawet w wielu dziwnych sytuacjach, używając wbudowanego Arel Railsów .
Spowoduje to scalenie obu relacji ActiveRecord przy użyciu metody Arel lub .
Merge, jak tu zasugerowano, nie działa dla mnie. Usunął z wyników drugi zestaw obiektów relacji.
źródło
Istnieje klejnot o nazwie active_record_union, który może być tym, czego szukasz.
Oto przykładowe zastosowania:
źródło
ransack
iacts-as-taggable-on
utrzymując swojeActiveRecord
instancje nienaruszone.Oto jak sobie z tym poradziłem, jeśli użyjesz pluck, aby uzyskać identyfikator dla każdego z rekordów, połączyć tablice razem, a następnie wykonać zapytanie o te połączone identyfikatory:
źródło
Jeśli masz tablicę aktywnych relacji rekordów i chcesz je wszystkie scalić, możesz to zrobić
źródło
array.inject(:merge)
nie działał dla tablicy aktywnych relacji rekordów w szynach 5.1.4. Alearray.flatten!
zrobił.Brute force it:
źródło