Wenn es eine mehrstufige Kategorie wie "Fleisch> Huhn> Fleisch" gibt Nachdem ich die Fleischkategorie im Rezept registriert hatte, implementierte ich eine Funktion, um auch die übergeordnete Kategorie "Fleisch> Huhn" zu zählen.
Ich konnte keinen Artikel finden, der einer mehrstufigen Kategorie mithilfe von Vorfahren einen Zähler hinzufügte. Deshalb habe ich ihn selbst gesucht und implementiert, damit ich ihn erläutern kann.
Wenn Sie eine ähnliche Person haben, beziehen Sie sich bitte darauf.
Ruby: 2.6.6
Rails: 6.0.2.2
Wir erstellen eine Website zum Veröffentlichen von Rezepten.
Es gibt eine Rezept-DB und eine Kategorie-DB.
Rezept hat mehrere Kategorien. (Zwischentabelle)
Die Kategorie ist eine mehrstufige Kategorie. Beispiel: Fleisch> Huhn> Fleisch
Implementiert mit Abstammung (Routenaufzählungsmodell)
Ein Zähler ist implementiert, um zu sehen, wie viele Rezepte es in einer Kategorie gibt.
ancestry: 3.0.7
counter_culture: 2.5.1
Klicken Sie hier für die Einführung von counter_culture. Aggregation der Anzahl verwandter Datensätze (Counter-Cache) - Qiita
Recipes Table
Table name: recipes
id :bigint not null, primary key
title :string not null
description :string not null
Zwischentabelle zwischen Rezept und Kategorie Für ein Rezept sind mehrere Kategorien registriert.
Table name: recipe_categories
id :bigint not null, primary key
recipe_id :bigint not null
category_id :bigint not null
Categories Table
Table name: categories
id :bigint not null, primary key
name :string not null
ancestry :string
recipes_count :integer default(0), not null
Model
class Recipe < ApplicationRecord
has_many :recipe_categories, dependent: :destroy
end
class Category < ApplicationRecord
has_ancestry
has_many :recipe_categories, dependent: :destroy
end
class RecipeCategory < ApplicationRecord
belongs_to :recipe
belongs_to :category
counter_culture :category, column_name: :recipes_count
end
Wenn es sich um eine 1: 1-Beziehung handelt, wird sie gezählt, indem Folgendes in die Zwischentabelle eingetragen wird.
counter_culture :category, column_name: :recipes_count
Dieses Mal möchte ich eine Funktion hinzufügen, die gleichzeitig die übergeordnete Kategorie zählt.
Zum Beispiel Das Rezept für Teruyaki-Hühnchen enthält eine Fleischkategorie.
Recipe.find(1)
=> #<Recipe
id: 1,
title: "Teriyaki Hähnchen"
>
RecipeCategory.find(1)
=> #<RecipeCategory
id: 1,
recipe_id: 1,
category_id: 20
>
Category.find(20)
=> #<Category
id: 20,
name: "Brustfleisch",
ancestry: "1/10",
recipes_count: 1
>
Die Fleischkategorie hat die folgende Beziehung.
id:1 > id:10 > id:20 Fleisch> Huhn> Brust
"Fleisch", das einem 1: 1-Zähler zugeordnet ist, wird gezählt, nicht jedoch "Fleisch" und "Huhn". Ich habe versucht, es so zu implementieren, dass auch die übergeordneten Kategorien "Fleisch" und "Huhn" gezählt werden.
Abschließend habe ich es so umgesetzt.
class RecipeCategory < ApplicationRecord
belongs_to :recipe
belongs_to :category
counter_culture :category, column_name: :recipes_count,
foreign_key_values: proc { |category_id| Category.find(category_id).path_ids }
end
Foreign_key_values
ist eine Option zum Überschreiben externer Schlüssel.
Die normalerweise zugeordnete "category_id: 20" wird zum externen Schlüssel, und die Anzahl der Kategorie-IDs: 20 erhöht oder verringert sich. Wenn Sie eine Zahl im Array-Format an "Foreign_key_values" übergeben, wird der übergebene Wert als externer Schlüssel verwendet, um die Anzahl aller Ziele zu erhöhen oder zu verringern.
Da wir alle übergeordneten und untergeordneten Kategorien zählen möchten, implementieren wir sie, indem wir im Beispiel den Wert "[1, 10, 20]" übergeben.
Ich bezog mich auf die offizielle Referenz und den Artikel, der übersetzt und erklärt wurde. GitHub - magnusvk/counter_culture: Turbo-charged counter caches for your Rails app. Hochleistungszähler-Cache für Rails gem'counter_culture 'README (Übersetzung) | TechRacho
foreign_key_values: proc { |category_id| Category.find(category_id).path_ids }
proc { |category_id| }
Übergeben Sie zuerst das Argument mit proc, zu diesem Zeitpunkt ist es der normale externe Schlüssel (in diesem Fall 20
).
Category.find(category_id)
Holen Sie sich das Zieldatensatzobjekt.
.path_ids
Wenn Sie "path_ids" mit der Funktion der Abstammung ausführen, können Sie die ID der Eltern-Kind-Beziehung des Objekts in einer Liste abrufen.
Referenz: [Übersetzung] Gem Ancestry Official Document --Qiita
Wenn Sie es ausführen, können Sie sehen, dass => [1, 10, 20]
zurückgegeben wird.
Category.find(20).path_ids
Category Load (1.0ms) SELECT "categories".* FROM "categories" WHERE "categories"."id" = $1 LIMIT $2 [["id", 20], ["LIMIT", 1]]
=> [1, 10, 20]
Durch Übergeben von "[1, 10, 20]" an "Foreign_key_values:" können jetzt alle Eltern-Kind-Kategorien gezählt werden.
counter_culture
hat eine Funktion zum Neuberechnen der Anzahl, counter_culture_fix_counts
.
Ich verwende es, um vorhandene Daten zu zählen und Zählabweichungen zu korrigieren, aber ich kann diese Funktion nicht mit der Option "Foreign_key_values" verwenden.
RecipeCategory.counter_culture_fix_counts
=> Fixing counter caches is not supported when using :foreign_key_values;
you may skip this relation with :skip_unsupported => true
Nach der Untersuchung scheint es bei der Verwendung von "Foreign_key_values" keine andere Wahl zu geben, als die Neuberechnungsfunktion selbst zu implementieren, also habe ich versucht, sie zu implementieren.
Aus dem Fazit habe ich es so umgesetzt. Da alles neu berechnet wurde, kann es in vielen Fällen einige Zeit dauern. Bitte lassen Sie mich wissen, ob es eine gute Implementierungsmethode gibt.
class RecipeCategory < ApplicationRecord
#...
#Kategorie Rezepte_Berechnen Sie alle Zählungen neu
def self.fix_counts
Category.update_all(recipes_count: 0)
target_categories = pluck(:category_id)
#Berechnen Sie die Anzahl der Kategorien=> { 1: 10, 10: 3, 20: 1 }
count_categories = target_categories.group_by(&:itself).transform_values(&:size)
count_categories.each do |category_id, count|
count_up_categories = Category.find(category_id).path_ids
Category.update_counters(count_up_categories, recipes_count: count)
end
end
end
Die Inhalte, die ausgeführt werden, sind wie folgt.
Für die Methode zur Berechnung der Zahl 3 habe ich auf den folgenden Artikel verwiesen. Zählen Sie, wie viele identische Elemente in einem Array-Patorash-Blog enthalten sind
Informationen zum Erhöhen der Anzahl von 5 um die Zahl finden Sie im folgenden Artikel. [Rails + MySQL] Counter-Implementierung [Wenn nicht, möchte ich eine neue erstellen, und wenn ja, möchte ich sie entsprechend erhöhen] --Qiita ActiveRecord::CounterCache::ClassMethods
Wenn Sie nun "RecipeCategory.fix_counts" ausführen, wird die Anzahl neu berechnet.
Durch Setzen von RecipeCategory auf Folgendes konnten wir die Zählerfunktion für die Eltern-Kind-Kategorie implementieren.
class RecipeCategory < ApplicationRecord
belongs_to :recipe
belongs_to :category
counter_culture :category, column_name: :recipes_count,
foreign_key_values: proc { |category_id| Category.find(category_id).path_ids }
#Kategorie Rezepte_Berechnen Sie alle Zählungen neu
def self.fix_counts
Category.update_all(recipes_count: 0)
target_categories = pluck(:category_id)
#Berechnen Sie die Anzahl der Kategorien=> { 100: 3, 102: 2 }
count_categories = target_categories.group_by(&:itself).transform_values(&:size)
count_categories.each do |category_id, count|
count_up_categories = Category.find(category_id).path_ids
Category.update_counters(count_up_categories, recipes_count: count)
end
end
end
Bitte nehmen Sie Bezug darauf. Wenn Sie FBs oder Verbesserungen haben, teilen Sie uns dies bitte in den Kommentaren mit.