2009-09-03 10 views
38

Est-ce que quelqu'un sait comment déterminer si une association Rails a été chargée?Comment faire pour déterminer si l'association Rails est surchargée?

Ma situation: J'ai un jeu de résultats où parfois l'une des associations est chargée, et parfois non. Si ce n'est pas le cas, je veux rechercher des associations en utilisant la recherche d'ActiveRecord. Si elle est chargée, je veux utiliser détecter. Par exemple, disons que j'ai un tableau "has_many" d'objets shipping_info dans mon modèle d'objet. Puis:

Si l'élément est charge désireux chargé, le plus efficace est:

item.shipping_infos.detect { |si| si.region == "United States" } 

Si l'article n'est pas impatient chargé, la charge la plus efficace est:

item.shipping_infos.where(region: "United States").first 

Mais à moins que je sais que ce est impatient chargé, je ne sais pas quel code appeler pour obtenir le record efficacement. Si j'utilise la première méthode alors qu'elle n'était pas très sollicitée, je dois rechercher plus d'enregistrements DB que nécessaire. Et si j'utilise la seconde méthode quand elle était chargée, mes objets chargés sont ignorés.

Répondre

41

item.shipping_infos.loaded? vous le dira.

Je dois dire, cependant: ce chemin mène à la folie ... avant d'écrire du code qui teste loaded? décider entre #detect et #find, assurez-vous que cette instance vraiment questions, par rapport à tout ce qui se passe.

Si ce n'est pas la chose la plus lente de votre application, l'ajout de chemins de code supplémentaires ajoute une complexité inutile. Juste parce que vous pourriez perdre un peu d'effort de base de données ne signifie pas que vous avez besoin de le réparer - il n'a probablement pas d'importance de façon mesurable.

+0

Merci Bryan. Je comprends d'où tu viens. Ce code particulier se trouve être dans le plus souvent appelé partiel dans notre application entière, cependant, raser même microsecondes fait une différence mesurable. Je vais donner #loaded? un essai. – wbharding

+9

Cela ne fonctionnera que pour has_many associations! Dans le cas de belongs_to cet appel chargera réellement l'autre objet (ainsi ce sera toujours vrai) – reto

2

Regardez le Bullet gem.. Cela vous dira quand vous devriez et ne devez pas utiliser le chargement impatient.

+0

Bullet s'est avéré très utile, même si j'ai fait très peu d'autres optimisations de DB pour le moment. Au moins, il se débarrasse de certaines lignes inutiles dans la sortie de la console. ;) – lime

+0

Le lien du plugin Bullet est mort. –

3

Vous pouvez détecter si une association unique a été chargée ou non foo? Par exemple, si shipping_info était une association belongs_to, alors item.loaded_shipping_info? retournera vrai quand il a été chargé. Curieusement, il semble renvoyer nil (plutôt que faux) quand il n'a pas été chargé (dans Rails 2.3.10 de toute façon).

+3

Cela a été supprimé dans Rails 3.1: https://github.com/rails/rails/issues/472 – Forrest

2

solution à ce problème devrait être foo.association(:bla).loaded?, mais il ne fonctionne pas correctement - il vérifie et marques association sale:

class Foo; has_one :bla, :autosave => true end 
foo.association(:bla).loaded? #=> false 
foo.save # saves foo and fires select * from bla 

J'ai ajouté suivant extension ActiveRecord:

module ActiveRecord 
    class Base 
    def association_loaded?(name) 
     association_instance_get(name).present? 
    end 
    end 
end 

et maintenant:

class Foo; has_one :bla, :autosave => true end 
foo.association_loaded?(:bla) #=> false 
foo.save # saves foo 
+0

Vous devez vérifier qu'il s'agit toujours d'un problème et mettre à jour la réponse pour l'étendre aux versions Rails appropriées. J'étais incapable de reproduire. –

+0

Toujours un problème à partir de Rails 4.2.6. Je ne sais pas si Rails 5 l'a. – Omnilord

+0

Quelle est la conséquence de la marquer comme sale? Juste une déclaration de sélection supplémentaire? Ou y a-t-il plus de mal à cela? – lulalala

19

Je vous suggère d'utiliser item.association_ cache.keys qui fournira une liste des associations chargées désirées. Donc vous item.association_cache.keys.include?: name_of_association

+1

Solution parfaite. Dabogert vous êtes le roi :) – Benj

+0

Wow, ne peut pas croire que j'avais manqué cela. Cela fonctionne pour les cas où l'association n'est pas chargée, mais il existe un cache en mémoire (par exemple lorsque vous construisez un objet en utilisant l'association). –

Questions connexes