Ich frage mich, wie ich eindeutige Datensätze aus has_many über eine Beziehung in Rails3 am besten anzeigen kann.
Ich habe drei Modelle:
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
Nehmen wir an, ich möchte alle Produkte, die ein Kunde bestellt hat, auf seiner Ausstellungsseite auflisten.
Möglicherweise haben sie einige Produkte mehrmals bestellt, daher verwende ich counter_cache, um sie in absteigender Reihenfolge anzuzeigen, basierend auf der Anzahl der Bestellungen.
Wenn sie jedoch ein Produkt mehrmals bestellt haben, muss ich sicherstellen, dass jedes Produkt nur einmal aufgeführt wird.
@products = @user.products.ranked(:limit => 10).uniq!
Funktioniert, wenn für ein Produkt mehrere Bestelldatensätze vorhanden sind, generiert jedoch einen Fehler, wenn ein Produkt nur einmal bestellt wurde. (Rang ist die an anderer Stelle definierte benutzerdefinierte Sortierfunktion)
Eine andere Alternative ist:
@products = @user.products.ranked(:limit => 10, :select => "DISTINCT(ID)")
Ich bin nicht sicher, ob ich hier auf dem richtigen Weg bin.
Hat jemand anderes das angegangen? Auf welche Probleme sind Sie gestoßen? Wo kann ich mehr über den Unterschied zwischen .unique erfahren? und DISTINCT ()?
Was ist der beste Weg, um eine Liste eindeutiger Datensätze über eine has_many-Beziehung zu generieren?
Vielen Dank
quelle
has_many :products, :through => :orders, :uniq => true
ist veraltet. Stattdessen sollten Sie jetzt schreibenhas_many :products, -> { uniq }, through: :orders
.DISTINCT
undORDER BY
Klauseln bekommen, können Sie immer verwendenhas_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
du es sonst bekommstrails ActiveRecord::StatementInvalid: PG::UndefinedFunction: ERROR: could not identify an equality operator for type json
Beachten Sie, dass
uniq: true
dies abhas_many
Rails 4 aus den gültigen Optionen entfernt wurde .In Rails 4 müssen Sie einen Bereich angeben, um diese Art von Verhalten zu konfigurieren. Zielfernrohre können wie folgt über Lambdas geliefert werden:
Die Rails-Anleitung behandelt diese und andere Möglichkeiten, wie Sie Bereiche verwenden können, um die Abfragen Ihrer Beziehung zu filtern. Scrollen Sie nach unten zu Abschnitt 4.3.3:
http://guides.rubyonrails.org/association_basics.html#has-many-association-reference
quelle
undefined method 'except' for #<Array...
und es war, weil ich.uniq
anstelle von.distinct
Sie könnten verwenden
group_by
. Zum Beispiel habe ich einen Fotogalerie-Einkaufswagen, für den ich möchte, dass Bestellartikel nach welchem Foto sortiert werden (jedes Foto kann mehrmals und in verschiedenen Druckgrößen bestellt werden). Dies gibt dann einen Hash mit dem Produkt (Foto) als Schlüssel zurück und jedes Mal, wenn es bestellt wurde, kann es im Kontext des Fotos aufgelistet werden (oder nicht). Mit dieser Technik können Sie tatsächlich eine Bestellhistorie für jedes Produkt ausgeben. Ich bin mir nicht sicher, ob das für Sie in diesem Zusammenhang hilfreich ist, aber ich fand es sehr nützlich. Hier ist der Code@order_items_by_photo
dann sieht ungefähr so aus:Sie könnten also so etwas tun:
Wenn Sie dies in Ihrer Ansicht sehen, durchlaufen Sie einfach Folgendes:
Auf diese Weise vermeiden Sie das Problem, das bei der Rücksendung nur eines Produkts auftritt, da Sie immer wissen, dass ein Hash mit einem Produkt als Schlüssel und einer Reihe Ihrer Bestellungen zurückgegeben wird.
Es ist vielleicht übertrieben für das, was Sie versuchen, aber es gibt Ihnen einige nette Optionen (z. B. bestellte Daten usw.), mit denen Sie zusätzlich zur Menge arbeiten können.
quelle
Auf Rails 6 habe ich das perfekt zum Laufen gebracht:
Ich konnte keine der anderen Antworten zur Arbeit bringen.
quelle