2010-06-13 2 views
2

Deux modèles (Rails 2.3.8):rails named_scope ne tient pas compte de chargement désireux

  • utilisateur; nom d'utilisateur & propriétés désactivées; Utilisateur has_one: profil
  • Profil; full_name & propriétés cachées

J'essaie de créer un named_scope qui élimine les profils utilisateur disabled = 1 et hidden = 1. Le modèle User est généralement utilisé en conjonction avec le modèle Profile, donc j'essaye de charger rapidement le modèle Profile (: include =>: profile).

J'ai créé un named_scope sur le modèle de l'utilisateur appelé « visible »:

named_scope :visible, { 
    :joins => "INNER JOIN profiles ON users.id=profiles.user_id", 
    :conditions => ["users.disabled = ? AND profiles.hidden = ?", false, false] 
} 

J'ai remarqué que lorsque j'utilise la named_scope dans une requête, l'instruction de chargement avide est ignorée.

Variation 1 - modèle utilisateur uniquement:

# UserController 
@users = User.find(:all) 

# User's Index view 
<% for user in @users %> 
    <p><%= user.username %></p> 
<% end %> 

# generates a single query: 
SELECT * FROM `users` 

Variation 2 - utiliser le modèle d'un profil en vue; charge paresseux modèle de profil

# UserController 
@users = User.find(:all) 

# User's Index view 
<% for user in @users %> 
    <p><%= user.username %></p> 
    <p><%= user.profile.full_name %></p> 
<% end %> 

# generates multiple queries: 
    SELECT * FROM `profiles` WHERE (`profiles`.user_id = 1) ORDER BY full_name ASC LIMIT 1 
    SHOW FIELDS FROM `profiles` 
    SELECT * FROM `profiles` WHERE (`profiles`.user_id = 2) ORDER BY full_name ASC LIMIT 1 
    SELECT * FROM `profiles` WHERE (`profiles`.user_id = 3) ORDER BY full_name ASC LIMIT 1 
    SELECT * FROM `profiles` WHERE (`profiles`.user_id = 4) ORDER BY full_name ASC LIMIT 1 
    SELECT * FROM `profiles` WHERE (`profiles`.user_id = 5) ORDER BY full_name ASC LIMIT 1 
    SELECT * FROM `profiles` WHERE (`profiles`.user_id = 6) ORDER BY full_name ASC LIMIT 1 

Variation 3 - charge désireux modèle de profil

# UserController 
    @users = User.find(:all, :include => :profile) 

    #view; no changes 

    # two queries 
    SELECT * FROM `users` 
    SELECT `profiles`.* FROM `profiles` WHERE (`profiles`.user_id IN (1,2,3,4,5,6)) 

Variation 4 - Utilisation name_scope, y compris l'instruction désireux de chargement

#UserConroller 
    @users = User.visible(:include => :profile) 

    #view; no changes 

    # generates multiple queries 
    SELECT `users`.* FROM `users` INNER JOIN profiles ON users.id=profiles.user_id WHERE (users.disabled = 0 AND profiles.hidden = 0) 
    SELECT * FROM `profiles` WHERE (`profiles`.user_id = 1) ORDER BY full_name ASC LIMIT 1 
    SELECT * FROM `profiles` WHERE (`profiles`.user_id = 2) ORDER BY full_name ASC LIMIT 1 
    SELECT * FROM `profiles` WHERE (`profiles`.user_id = 3) ORDER BY full_name ASC LIMIT 1 
    SELECT * FROM `profiles` WHERE (`profiles`.user_id = 4) ORDER BY full_name ASC LIMIT 1 

Variation 4 ne renvoie le nombre correct des enregistrements, mais semble également ignorer l'instruction de chargement enthousiaste.

Est-ce un problème avec les étendues nommées inter-modèles? Peut-être que je ne l'utilise pas correctement.

Est-ce que ce genre de situation est mieux géré par Rails 3?

Répondre

4

De railsapi.com:

chargement Désireuse des associations

[...] Comme une seule table est chargée à un moment, conditions ou commandes ne peut pas faire référence à des tables autres que les principal. Si tel est le cas Active Le dossier revient à la stratégie précédemment utilisée. Par exemple

Post.find(:all, :include => [ :author, :comments ], :conditions => ['comments.approved = ?', true])

se traduira par une seule requête SQL avec rejoint le long des lignes de: LEFT OUTER JOIN Commentaires sur comments.post_id = posts.id et LEFT OUTER JOIN auteurs sur les auteurs. id = posts.author_id.

Je crois que cela répond à votre question ... il n'y a pas de chargement désireux de « variation # 4 » parce que vous profiles références que sur votre tableau named_scope.

+0

OK. Je pourrais déplacer l'attribut caché vers le modèle User pour éviter complètement cette situation, mais il vaut probablement mieux que je trouve une autre approche pour ce type de situation. Pouvez-vous en penser un? – craig

+1

Vous pouvez créer une autre association: 'User has_one: visible_profile'. Ensuite, vous appelez @ user.visible (: include =>: visible_profile), quand 'visible' est le named_scope avec seulement cette condition:' ["disabled =?", False] '. C'est comme l'exemple sur 'railsapi.com'. –

+0

@j: J'ai ajouté une association au modèle User - has_one: visible_profile,: class_name => 'Profile',: conditions => ["profiles.hidden =?", False]. Changé le modèle d'utilisateur named_scope - named_scope: visible, { : conditions => ["disabled =?", False] } modifié l'action d'index UserController - @users = User.visible (: all,: include =>: visible_profile) . Serveur redémarré. Chargement paresseux qui se produit encore. Filtre de modèle de profil ignoré. Pensées? – craig

Questions connexes