6
votes

Comment mettre à jour compteur_cache lors de la mise à jour d'un modèle?

J'ai une relation simple: xxx

disons que j'ai deux conteneurs. Je crée un article et associez-le avec le premier conteneur. Le compteur est augmenté.

Puis je décide de l'associer à l'autre conteneur à la place. Comment mettre à jour la colonne Éléments_count des deux conteneurs?

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?


0 commentaires

8 Réponses :


3
votes

Cela devrait fonctionner automatiquement. Lorsque vous mettez à jour items.container_id , 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: xxx

upd

pour démontrer le comportement natif: xxx < p> Cela devrait fonctionner sans piratage. De la boîte.


0 commentaires

2
votes

pour les rails 3.1 utilisateurs. Avec Rails 3.1, la réponse ne fonctionne pas. Les œuvres suivantes pour moi. XXX


0 commentaires

1
votes

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


1 commentaires

Cela lancera probablement une erreur si le conteneur_id / conteneur_was est nul.



1
votes

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 Lib /fix_counters_update.rb code> avec les éléments suivants: p> xxx pré>

Le code ci-dessus utilise le ActiveModel :: Dirty Méthode 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>

Ajouter aux initialiseurs strong> P>

Créez un nouveau fichier config / initialiseurs / active_record_extensions.rb code> avec les éléments suivants: p>

nécessite 'fix_update_counters' code> p>

Ajouter aux modèles forts> p>

pour chaque modèle que vous souhaitez que les compteurs mis à jour ajoutez le rappel: p>

class Comment < ActiveRecord::Base
  after_update :fix_updated_counters
  ....
end


0 commentaires

1
votes

Ici, la solution @Curley pour fonctionner avec des modèlesPaché des noms de noms. XXX


0 commentaires

3
votes

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)


1 commentaires

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.



2
votes

Voici une approche qui fonctionne bien pour moi dans des situations similaires xxx

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


0 commentaires

1
votes

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.

Voici une autre suggestion (presque similaire à Satish): xxx


0 commentaires