J'ai une relation simple: disons que j'ai deux conteneurs. Je crée un article et associez-le avec le premier conteneur. Le compteur est augmenté. P> Puis je décide de l'associer à l'autre conteneur à la place. Comment mettre à jour la colonne Éléments_count des deux conteneurs? P> J'ai trouvé une solution possible à http://railforum.com/viewtopic.php?id=39285 .. Cependant, je suis débutant et je ne comprends pas. Est-ce le seul moyen de le faire? P> p>
8 Réponses :
Cela devrait fonctionner automatiquement. Lorsque vous mettez à jour upd fortre> p> pour démontrer le comportement natif: p> items.container_id code>, il décompose le comptoir de l'ancien conteneur et l'incrustion nouvelle. Mais si ça ne fonctionne pas - c'est étrange. Vous pouvez essayer ce rappel:
pour les rails 3.1 utilisateurs.
Avec Rails 3.1, la réponse ne fonctionne pas.
Les œuvres suivantes pour moi.
Mises à jour de @ Fl00R Réponse
class Container
has_many :items_count
end
class Item
belongs_to :container, :counter_cache => true
after_update :update_counters
private
def update_counters
if container_id_changed?
Container.increment_counter(:items_count, container_id)
Container.decrement_counter(:items_count, container_id_was)
end
# other counters if any
...
...
end
end
Cela lancera probablement une erreur si le conteneur_id / conteneur_was est nul.
J'ai récemment rencontré le même problème (rails 3.2.3). On dirait que cela n'a pas encore été corrigé, alors je devais aller de l'avant et faire un correctif. Ci-dessous, comment j'ai modifié ActiveCord :: Base et utilise After_Update Callback pour conserver mes compteurs_caches en synchronisation.
EXTENDY EXTENDY EXTENDY EXTRÊME :: BASE P> P> Créer un nouveau fichier Le code ci-dessus utilise le ActiveModel :: Dirty Méthode Ajouter aux initialiseurs strong> P> Créez un nouveau fichier pour chaque modèle que vous souhaitez que les compteurs mis à jour ajoutez le rappel: p> Lib /fix_counters_update.rb code> avec les éléments suivants: p> Modifications code> qui renvoie un hachage contenant l'attribut modifié et une matrice de la valeur ancienne et de la nouvelle valeur. En testant l'attribut pour voir s'il s'agit d'une relation (c'est-à-dire la fin avec / _id /), vous pouvez déterminer conditionnellement si décryptement_counter ou incrément_counter code> doit être exécuté. Il est essier de tester la présence de nil code> dans la matrice, sinon les erreurs résulteront. P> config / initialiseurs / active_record_extensions.rb code> avec les éléments suivants: p> nécessite 'fix_update_counters' code> p> class Comment < ActiveRecord::Base
after_update :fix_updated_counters
....
end
Ici, la solution @Curley pour fonctionner avec des modèlesPaché des noms de noms.
modifié un bit pour gérer les noms de cache de contre-cache personnalisés
(N'oubliez pas d'ajouter après_update: fix_updated_counter code> sur les modèles à l'aide de compteur_cache) module FixUpdateCounters
def fix_updated_counters
self.changes.each { |key, (old_value, new_value)|
# key should match /master_files_id/ or /bibls_id/
# value should be an array ['old value', 'new value']
if key =~ /_id/
changed_class = key.sub /_id$/, ''
association = self.association changed_class.to_sym
case option = association.options[ :counter_cache ]
when TrueClass
counter_name = "#{self.class.name.tableize}_count"
when Symbol
counter_name = option.to_s
end
next unless counter_name
association.klass.decrement_counter(counter_name, old_value) if old_value
association.klass.increment_counter(counter_name, new_value) if new_value
end
} end end
ActiveRecord::Base.send(:include, FixUpdateCounters)
Cette réponse est la plus dynamique et serait la meilleure pour les projets avec beaucoup de caches compteurs qui incluent des noms personnalisés. Pour Martin, la réponse acceptée peut être plus facile.
Voici une approche qui fonctionne bien pour moi dans des situations similaires Informations supplémentaires sur le module d'objet sale http://api.rubyonrails.org/classes/activemodel/dirty.html et une ancienne vidéo sur eux http://railcastss.com/eepisodes/109-tracking-atribute-changes et documentation sur réinitialiser_counters http://apidock.com/rail/v3.2.8/acterecord/countercache/reset_counters P> p>
Désolé, je n'ai pas assez de réputation pour commenter les réponses.
À propos de Fl00R, je peux voir un problème s'il y a une erreur et enregistrer retour "False", le compteur a déjà été mis à jour, mais il n'aurait pas dû être mis à jour.
Je me demande donc si "After_update: update_counters" est plus approprié.
La réponse de Curley fonctionne, mais si vous êtes dans mon cas, soyez prudent car il vérifiera toutes les colonnes avec "_ID". Dans mon cas, il met automatiquement la mise à jour d'un champ que je ne souhaite pas être mis à jour. P>
Voici une autre suggestion (presque similaire à Satish): p>