Zastanawiam się, jaki jest najlepszy sposób wyświetlania unikalnych rekordów z has_many, poprzez relację w Rails3.
Mam trzy modele:
class User < ActiveRecord::Base
has_many :orders
has_many :products, :through => :orders
end
class Products < ActiveRecord::Base
has_many :orders
has_many :users, :through => :orders
end
class Order < ActiveRecord::Base
belongs_to :user, :counter_cache => true
belongs_to :product, :counter_cache => true
end
Powiedzmy, że chcę wymienić wszystkie produkty zamówione przez klienta na jego stronie pokazu.
Mogli wielokrotnie zamawiać niektóre produkty, więc używam counter_cache do wyświetlania w kolejności malejącej, na podstawie liczby zamówień.
Ale jeśli zamówili produkt wiele razy, muszę upewnić się, że każdy produkt jest wymieniony tylko raz.
@products = @user.products.ranked(:limit => 10).uniq!
działa, gdy istnieje wiele rekordów zamówień na produkt, ale generuje błąd, jeśli produkt został zamówiony tylko raz. (ranking to niestandardowa funkcja sortowania zdefiniowana w innym miejscu)
Inną alternatywą jest:
@products = @user.products.ranked(:limit => 10, :select => "DISTINCT(ID)")
Nie jestem pewien, czy mam tutaj właściwe podejście.
Czy ktoś jeszcze się tym zajął? Jakie problemy napotkaliście? Gdzie mogę dowiedzieć się więcej o różnicy między .unique! i DISTINCT ()?
Jaki jest najlepszy sposób na wygenerowanie listy unikatowych rekordów za pomocą has_many, poprzez relację?
Dzięki
źródło
has_many :products, :through => :orders, :uniq => true
jest przestarzały. Zamiast tego powinieneś teraz napisaćhas_many :products, -> { uniq }, through: :orders
.DISTINCT
iORDER BY
, zawsze możesz użyćhas_many :products, -> { unscope(:order).distinct }, through: :orders
has_many :subscribed_locations, -> { unscope(:order).select("DISTINCT ON (locations.id) locations.*") },through: :people_publication_subscription_locations, class_name: 'Location', source: :location
inaczej otrzymaszrails ActiveRecord::StatementInvalid: PG::UndefinedFunction: ERROR: could not identify an equality operator for type json
Zauważ, że
uniq: true
zostało usunięte z poprawnych opcjihas_many
w Rails 4.W Railsach 4 musisz podać zakres, aby skonfigurować tego rodzaju zachowanie. Zakresy mogą być dostarczane przez lambdy, na przykład:
Przewodnik po railsach omawia ten i inne sposoby wykorzystania zakresów do filtrowania zapytań relacji, przewiń w dół do sekcji 4.3.3:
http://guides.rubyonrails.org/association_basics.html#has-many-association-reference
źródło
undefined method 'except' for #<Array...
i to dlatego, że.uniq
zamiast.distinct
Możesz użyć
group_by
. Na przykład mam koszyk z galerią zdjęć, dla którego chcę, aby pozycje były sortowane według tego, które zdjęcie (każde zdjęcie można zamówić wiele razy i na odbitkach w różnych rozmiarach). To następnie zwraca hash z produktem (zdjęcie) jako klucz i za każdym razem, gdy został zamówiony, można go wymienić w kontekście zdjęcia (lub nie). Korzystając z tej techniki, można faktycznie wyświetlić historię zamówień dla każdego produktu. Nie jestem pewien, czy jest to pomocne w tym kontekście, ale uznałem to za całkiem przydatne. Oto kod@order_items_by_photo
wtedy wygląda mniej więcej tak:Możesz więc zrobić coś takiego:
Następnie, gdy zobaczysz to w swoim widoku, po prostu przejrzyj coś takiego:
W ten sposób unikniesz problemu występującego przy zwracaniu tylko jednego produktu, ponieważ zawsze wiesz, że zwróci on skrót z produktem jako kluczem i tablicą Twoich zamówień.
Może to być przesada, jeśli chodzi o to, co próbujesz zrobić, ale daje ci kilka fajnych opcji (np. Zamówione daty itp.) Do pracy oprócz ilości.
źródło
Na Rails 6 mam to, aby działało idealnie:
Żadne inne odpowiedzi nie zadziałały.
źródło