11
votes

Comment puis-je forcer les rails à ne pas utiliser de résultat mis en cache pour HAS_MANY à travers les relations?

J'ai les trois modèles suivants (massivement simplifié): xxx pré>

Il semble que A.CS soit mis en cache la première fois qu'il est utilisé (par objet) quand je préférerais pas. p>

Voici une session de console qui met en évidence le problème (le fluff a été édité) p>

d'abord, la façon dont il devrait fonctionner h2> xxx pré >

C'est bien comme vous l'attendez. L'A.CS va bien par la relation A.BS. P>

et maintenant pour les infiliations de mise en cache h2> xxx pré>

donc le premier appel à A2.cs (résultant dans une requête de DB) assez correctement renvoyée n ° CS. Le deuxième appel, cependant, montre un manque distinct de CS, même si elles soient bien que celles-ci (aucune requête de DB n'a eu lieu). P>

et juste pour tester ma santé mentale n'est pas à blâmer h2>
012 > A.find(a2.id).cs
=> [#<C id: 1, b_id: 1>]


0 commentaires

6 Réponses :


2
votes

(éditer: voir la réponse de Daniel Waltrip, c'est bien mieux que le mien)

Donc, après avoir tapé tout cela et juste vérifier quelque chose de sans rapport, mes yeux sont arrivés à la section "3.1 Contrôle de la mise en cache" de l'association Guide de base. < / P>

Je serai un bon garçon et je partagerai la réponse, car je viens de passer environ huit heures de googling infructueux frustrant.

Mais si vous voulez recharger le cache, car les données auraient pu être changé par une autre partie de la demande? Juste passer fidèle à la Appel d'association: xxx

donc la morale de l'histoire: RTFM; Tout cela.

EDIT: Donc, avoir à mettre vrai partout dans la place n'est probablement pas une si bonne chose car le cache serait contourné même quand il n'a pas besoin d'être. La solution présentée dans les commentaires de Daniel Waltrip est bien meilleure: utilisez Clear_association_cache xxx

Alors, non seulement nous devrions nous rechercher. Le code pour : nodoc: s!


4 commentaires

Ok, maintenant je suis de retour à mon code pour le réparer et je n'ai soudainement pas l'aimer. Y a-t-il un moyen de marquer le cache comme étalé? En utilisant le code ci-dessus, je ne veux pas avoir à la classe de litière A avec C (vrai) .blahblahblah partout à la place. Je préférerais avoir une seule fonction pour ajouter B's's et que cela marque n'importe quel CS Cached CS comme étant rassis.


clear_associiation_cache faire le tour? Je devais mettre cela dans quelques-uns de mes méthodes de modèle pour éviter d'avoir des données stables dans le cache de requête. Bien que je me sens comme même ce n'est pas la solution la plus élégante.


C'est beaucoup mieux que ma solution. En nettoyant le cache, je n'ai pas à faire en sorte que le cache soit contourné partout. Je fais, cependant encore une légère frustration avec elle: si A avait deux associations (dire has_many: DS ), a2.clear_association_cache soufflerait également le CS et ds. Maintenant, si seulement Clear_associiation_Cache devait prendre un paramètre pour invalider le cache spécifié, la vie serait merveilleuse.


J'ai trouvé une manière encore meilleure! Je l'ai posté comme solution: Stackoverflow.com/a/21320872/111635 =)



17
votes

J'ai fait plus de recherches sur cette question. Tout en utilisant clear_association_cache code> était suffisamment pratique, l'ajoutant après chaque opération annulée le cache ne s'est pas sentie au sec. Je pensais que les rails devraient pouvoir garder une trace de cela. Heureusement, il y a un moyen!

J'utiliserai vos modèles d'exemple: A (a beaucoup B, nombre de C à B), B (appartient à A, a plusieurs c) et C (appartient à B).

Nous devrons utiliser le Touch: TRUE CODE> Option pour le appartient à la méthode code>. Cette méthode met à jour l'attribut mis à jour code> sur le modèle parent, mais plus important encore, il déclenche également un après_touch code> rappel. Ce rappel nous permet d'effacer automatiquement le cache de l'association pour toute instance d'un lorsque une instance associée de B ou C est modifiée, créée ou détruite. P>

première modification du appartient à code> Appel de méthode pour B et C, ajout toucher: true code> p> xxx pré>

ajoutez un After_touch code> rappel sur un p >

class A < ActiveRecord::Base
  has_many :bs
  has_many :cs, through: :bs

  after_touch :clear_association_cache
end


4 commentaires

Fantastique! Merci de votre aide.


parfait, il suffit d'avoir ce problème exact sur mon application, au revoir la solution JavaScript laidée


@MattramireZ Solution JavaScript !? Wat? Que faisiez-vous?


Clear_association_Cache a été rendu privé dans Rails 5 Github.com/Rails/Rails/ COMMIT / 9D56958 alternatives possibles Inclure recharger et appeler réinitialiser sur l'association



3
votes

Toutes les méthodes d'association sont construites autour de la mise en cache, ce qui permet de conserver la requête la plus récente disponible pour d'autres opérations. Le cache est même partagé entre les méthodes. Par exemple: xxx

Mais si vous souhaitez recharger le cache, car des données auraient pu être modifiées par une autre partie de l'application? Il suffit de passer fidèle à l'appel de l'association: xxx

source http://guides.rubyonRails.org/association_basics.html


0 commentaires

2
votes

J'ai trouvé une autre façon de désactiver la cache de requête. Dans votre modèle, ajoutez simplement un par défaut_scope xxx

vérifié le fonctionnement localement. J'ai trouvé cela en regardant Active_Record code source dans actif_record / associations / association.rb : xxx


1 commentaires

Rails 5 besoin d'avoir quelque chose dans le défaut_scope; J'ai utilisé: par défaut_scope {tout}



0
votes

Pour effacer le cache, utilisez .reload xxx

source: Contrôle de la cache


0 commentaires

0
votes

Vous pouvez utiliser l'option étendre code> et fournir un module pour réinitialiser le chargement avant qu'il ne se produise comme:

  # Usage:
  # ---
  #
  # has_many :versions,
  #   ...
  #   extend: UncachedAssociation
  #

  module UncachedAssociation
    def load_target
      @association.reset
      super
    end
  end


0 commentaires