2009-04-17 3 views
2

Dans mon application actuelle, je retire beaucoup de données de la base de données pour que je puisse démarrer une tâche d'arrière-plan longue durée que je ne veux pas toucher la base de données 5 secondes.Mise à jour des associations chargées en mémoire

Tout cela fonctionne très bien mais j'ai un code inélégant dont je voudrais me débarrasser si possible. Par exemple, j'ai un modèle d'utilisateur et ce modèle d'utilisateur peut se lier à d'autres modèles d'utilisateurs sous la forme de contacts, qui à leur tour peuvent relier au premier modèle d'utilisateur et ainsi de suite. Ceci est modélisé comme suit (grâce à Milan Novota pour son aide plus tôt): -

class User < ActiveRecord::Base 
    has_many :contact_records, :foreign_key => :owner_id 
    has_many :contacts, :through => :contact_records, :class_name => "User" 
end 

class ContactRecord < ActiveRecord::Base 
    belongs_to :owner, :class_name => "User" 
    belongs_to :user 
end 

Alors maintenant, je peux taper

user_a_contacts = user_a.contact_records 
=> [user_b, user_c] 

et obtenir tous les contacts pour un utilisateur. Maintenant, disons que je veux obtenir les contacts de l'utilisateur b par l'utilisateur un son (ne peut pas penser pourquoi je mais c'est seulement un exemple!)

user_b_contacts = user_a_contacts.first.contact_records 
=> [user_a, user_c] 

Maintenant, je peux obtenir le nom d'un utilisateur (dans un alambiqué, rond-point, jamais -utiliser-dans-le-monde-réel)

user_a_name = user_b_contacts.first.name 
=> "Jamie" 

Jusqu'ici, tout va bien. Maintenant, je change utilisateur un son nom

user_a.name = "Sandy" 
=> "Sandy" 

Si vous accédez à un nom d'utilisateur à nouveau comme avant de la base de données que je reçois

user_a_name = user_b_contacts.first.name 
=> "Sandy" 

Cependant, si j'ai hâte chargé et gardé cette valeur en mémoire que je reçois

user_a_name = user_b_contacts.first.name 
=> "Jamie" 

mais faire ce qui suit me donne la bonne réponse

user_a.name 
=> "Sandy" 

De toute évidence, le chargement enthousiaste crée différents objets Utilisateur pour les utilisateurs d'origine et ceux qui sont désirés à partir des objets ContactRecord.

donc (enfin!) Ma question est la suivante: -

En ce moment, j'ai bodged autour de cela en utilisant

@users.each.detect{|user| user == user_b_contacts.first} 

(où @users est la liste avide chargé d'objets de l'utilisateur). Y at-il un moyen que je puisse mettre à jour les objets User impatients-chargés à la place?

S'il vous plaît noter: -

a) Je suis impatient de chargement en utilisant les éléments suivants

User.find(:all, :include => [ {:contact_records => :contacts] } ]) 

b) Il est évident que ce n'est pas le code réel que je travaille avec, mais il aurait été encore plus explication et exposition afin de montrer ce code et je pense que je t'ai assez ennuyé! Croyez-moi que le vrai exemple que j'utilise a besoin de cette structure pour fonctionner correctement, aussi bizarre que cela puisse paraître!;)

c) J'ai peut-être introduit des fautes de frappe et des erreurs lors de la reconstruction de l'exemple, mais veuillez les ignorer. Tout ce que j'ai besoin de savoir, c'est s'il est possible de recharger les utilisateurs impatients sans toucher à la base de données.

Un grand merci d'avance! MISE À JOUR: Comme mentionné ci-dessous, les données du modèle ne seront pas sauvegardées dans la base de données jusqu'à la fin du processus, de sorte que le rechargement ne fonctionnera pas car les données de la base de données n'auront pas changé.

Répondre

4

OK. Je vais condenser votre question en une nouvelle question et répondre à celle-ci. Pardonnez-moi si j'ai mal compris et ce n'est pas ce que vous demandez.

Question

Si user est un modèle ActiveRecord où je l'ai chargé une association contacts à l'avance avec User.first(:include => :contacts), comment puis-je rafraîchir l'association contacts quand il a changé dans la base de données?

Réponse

Vous pouvez invalider le cache d'association de deux façons que je connais. D'abord vous pouvez faire:

user.reload 

qui rechargera le modèle d'utilisateur entier à partir de zéro. Une façon de faire un peu moins drastique est de faire

user.clear_association_cache 

qui ne sera pas recharger tous user, mais effacera les associations mises en cache.

De toute façon, la prochaine fois que vous le ferez user.contacts, il les chargera à nouveau depuis la base de données.

0

Un grand merci pour votre réponse, Daniel. Tandis que vous n'avez pas encore la bonne question, vous m'avez fait réaliser que j'avais raté un point crucial! L'enregistrement de la base de données n'aura pas été mis à jour car je ne sauvegarde pas! à tout moment.

L'essentiel de ce que je fais est d'extraire les données du modèle dans des variables d'instance afin d'accélérer un processus d'arrière-plan. En tant que telles, les données chargées la première fois ne seront pas sauvegardées dans la base de données avant la fin du processus. Ce que j'espérais, c'était un moyen que vous pouviez spécifier en cas de chargement avide que la valeur d'une colonne se rapporte à un autre modèle déjà chargé.

Par exemple,

User.find(:all, :include => [ {:contact_records => (:contacts as User)] } ]) 

ou similaire. Pour autant que je sache, il n'y a pas de telle syntaxe dans Rails, mais j'espère que je me trompe! :)

Espérons que cela soit un peu plus clair et merci encore pour la réponse.

Questions connexes