10

Lorsque vous travaillez avec une association polymorphique, est-il possible d'exécuter un include sur des sous-modèles qui ne sont présents que dans certains types?Ruby on Rails:: inclure dans une association polymorphe avec des sous-modèles

Exemple:

class Container 
    belongs_to :contents, :polymorphic => true 
end 
class Food 
    has_one :container 
    belongs_to :expiration 
end 
class Things 
    has_one :container 
end 

De l'avis que je vais vouloir faire quelque chose comme:

<% c = Containers.all %> 
<% if c.class == Food %> 
    <%= food.expiration %> 
<% end %> 

Par conséquent, je voudrais à la charge de la hâte expirations quand je charge c , parce que je sais que j'en aurai besoin tous les derniers. Y a-t-il un moyen de le faire? Juste en définissant un régulier: include m'obtient des erreurs car tous les types fermés n'ont pas d'expiration de sous-modèle.

Répondre

24

Modifié réponse

J'ai récemment découvert que Rails supporte le chargement désireux d'associations polymorphes lorsque vous filtrez par la colonne de type polymorphes. Il n'est donc pas nécessaire de déclarer de fausses associations.

class Container 
    belongs_to :content, :polymorphic => true 
end 

requête Maintenant, le Container par container_type.

containers_with_food = Container.find_all_by_content_type("Food", 
          :include => :content) 

containers_with_thing = Container.find_all_by_content_type("Thing", 
          :include => :content) 

Vieille réponse

C'est un hack car il n'y a aucun moyen direct d'inclure les objets polymorphes dans une requête.

class Container 
    belongs_to :contents, :polymorphic => true 
    # add dummy associations for all the contents. 
    # this association should not be used directly 
    belongs_to :food 
    belongs_to :thing 
end 

requête Maintenant, le Container par container_type.

containers_with_food = Container.find_all_by_content_type("Food", 
          :include => :food) 

containers_with_thing = Container.find_all_by_content_type("Thing", 
          :include => :thing) 

que les résultats dans deux SQL appels à la base de données (en fait, il est 4 appels comme rails exécute un SQL pour chaque :include)

Il n'y a aucun moyen de le faire dans un SQL que vous avez besoin autre colonne définir pour différents types de contenu.

Avertissement: Les associations fictives sur la classe Content ne doivent pas être utilisées directement, car cela entraînera des résultats inattendus. Par exemple, le premier objet du tableau contents contient des aliments.

Content.first.food # will work 
Content.first.thing 

Le deuxième appel ne fonctionnera pas. Il peut vous donner un objet Thing avec le même ID que l'objet Food pointé par Content.

+0

J'ai mis à jour ma réponse en fonction de nouvelles informations, jetez un oeil. –

+1

Dans quelle version d'ActiveRecord le chargement des associations polymorphes est-il efficace? Cela ne fonctionne pas pour moi dans 3.2.3 – nicholaides

+0

@nicholaides Cela devrait fonctionner dans 3.2.3. Le chargement impatient ne se produit que lorsque vous filtrez par la colonne de type polymorphe. Quelle est l'erreur que vous avez rencontrée? –