Ich habe eine Methode, die Stats (hauptsächlich Summen) für eine Anzahl von Float-Attribute in einem Modell berechnet.Rails Summe auf AssociationRelation Attribut ist falsch, wenn die Assoziation limit Klausel
Die Modelle
class GroupPlayer < ActiveRecord::Base
belongs_to :group
has_many :scored_rounds
has_many :rounds, dependent: :destroy
end
class Round < ActiveRecord::Base
belongs_to :group_player
end
class ScoredRound < Round
# STI
end
Die Methode, die Statistik auf float-Attribute bis zu 4 sieht vor, dass von einem anderen Methode aufgerufen wird, je nachdem, ob ich Statistiken für einen Spieler oder eine Gruppe von Spielern bekommen. Ein erster Filter auf ScoredRound wird an die Methode übergeben (sr)
def method_stats(method,sr,grp)
rounds = sr.where.not(method => nil)
number_rounds = rounds.count
won = rounds.sum(method).round(2)
if method == :quality
dues = grp.options[:dues] * number_rounds
else
dues = grp.options["#{method.to_s}_dues"] * number_rounds
end
balance = (won - dues).round(2)
perc = dues > 0 ? (won/dues).round(3) : 0.0
[self.full_name,number_rounds,won,dues,balance,perc]
end
3 der 4 Attribute I in ScoredRounds bin Summieren kann nicht gesetzt ist (Null), wenn der Spieler nicht das Spiel gewonnen haben, so dass die Runden gefiltert werden .
Alles funktionierte gut, bis ich beschloss, ein Limit für die Anzahl der zu verwendenden Runden hinzuzufügen. Zum Beispiel, wenn ich nur Status für die letzten 25 Runden in der Abfrage übergeben method_stats
wollte würde ich nennen:
def money_stats(grp,method,limit=100)
sr = self.scored_rounds.where.not(method => nil).order(:date).reverse_order.limit(limit)
method_stats(method,sr,grp)
end
Auch hier habe ich nur noch die Grenze und um Klausel für die Abfrage. Funktionierte gut für alle Datensätze.
Wenn ich das Verfahren in der Konsole mit geführt unter Verwendung der oben genannten Methoden (oder mit ihnen!) Simulieren Ich werde eine fehlerhafte Summe erhalten
gp = GroupPlayer.find(123)
GroupPlayer Load (2.1ms) SELECT "group_players".* FROM "group_players" WHERE "group_players"."id" = $1 LIMIT $2 [["id", 123], ["LIMIT", 1]]
=> valid group player
sr = gp.scored_rounds.where.not(:quality => nil)
ScoredRound Load (1.7ms) SELECT "rounds".* FROM "rounds" WHERE "rounds"."type" IN ('ScoredRound') AND "rounds"."group_player_id" = $1 AND ("rounds"."quality" IS NOT NULL) [["group_player_id", 123]]
=> #<ActiveRecord::AssociationRelation [#<ScoredRound id: 5706, player_id: 123, group_player_id: 123, event_id: 12, type: "ScoredRound", date: "2016-11-04", team: 3, tee: "White", quota: 32, front: 15, back: 15, total: 30, created_at: "2016-11-04 14:18:27", updated_at: "2016-11-04 19:12:47", quality: 0.0, skins: nil, par3: nil, other: nil>,...]
sr.count
(1.5ms) SELECT COUNT(*) FROM "rounds" WHERE "rounds"."type" IN ('ScoredRound') AND "rounds"."group_player_id" = $1 AND ("rounds"."quality" IS NOT NULL) [["group_player_id", 123]]
=> 44
sr.sum(:quality)
(1.0ms) SELECT SUM("rounds"."quality") FROM "rounds" WHERE "rounds"."type" IN ('ScoredRound') AND "rounds"."group_player_id" = $1 AND ("rounds"."quality" IS NOT NULL) [["group_player_id", 123]]
=> 354.166666666667
# Now if I add the order and limit clause
sr = gp.scored_rounds.where.not(:quality => nil).order(:date).reverse_order.limit(25)
ScoredRound Load (1.6ms) SELECT "rounds".* FROM "rounds" WHERE "rounds"."type" IN ('ScoredRound') AND "rounds"."group_player_id" = $1 AND ("rounds"."quality" IS NOT NULL) ORDER BY "rounds"."date" DESC LIMIT $2 [["group_player_id", 123], ["LIMIT", 25]]
=> => #<ActiveRecord::AssociationRelation [...]
sr.count
(1.1ms) SELECT COUNT(count_column) FROM (SELECT 1 AS count_column FROM "rounds" WHERE "rounds"."type" IN ('ScoredRound') AND "rounds"."group_player_id" = $1 AND ("rounds"."quality" IS NOT NULL) LIMIT $2) subquery_for_count [["group_player_id", 123], ["LIMIT", 25]]
=> 25
sr.sum(:quality)
(1.8ms) SELECT SUM("rounds"."quality") FROM "rounds" WHERE "rounds"."type" IN ('ScoredRound') AND "rounds"."group_player_id" = $1 AND ("rounds"."quality" IS NOT NULL) LIMIT $2 [["group_player_id", 123], ["LIMIT", 25]]
=> 354.166666666667
### This is the error, it return the sum off all records,
# not the limited???? if I use pluck and sum
sr.pluck(:quality)
=> [10.0, 11.3333333333333, 10.0, 34.0, 0.0, 7.33333333333333, 0.0, 0.0, 31.5, 0.0, 21.3333333333333, 0.0, 19.0, 0.0, 0.0, 7.5, 0.0, 20.0, 10.0, 28.0, 8.0, 9.5, 0.0, 3.0, 24.0]
sr.pluck(:quality).sum
=> 254.49999999999994
Weiß nicht, ob ich einen Fehler in AREL gefunden oder Ich mache etwas falsch. Ich habe es mit nur Round anstelle der STI ScoredRound mit den gleichen Ergebnissen versucht.
Irgendwelche Ideen?
Vielen Dank für Ich fand tatsächlich einen einjährigen Beitrag, der nach der gleichen Frage fragte, und eine Antwort, die erklärte, dass das Limit nicht wirklich Teil der Abfrage ist [ActiveRecord Berechnungen auf Teilmengen oder Datensätzen] (http://stackoverflow.com/questions/37020161)/activerecord-Berechnungen-auf-Untermengen-oder-Aufzeichnungen). – appleII717