Question

J'utilise des associations polymorphiques pour suivre les commentaires de mon projet. Toutes choses très direct.

Le problème que j'ai est basé sur l'interrogation de l'association polymorphes et se joindre à partir du modèle de commentaire Retour à son propriétaire.

...

J'ai un modèle de commentaire

class Comment < ActiveRecord::Base
  belongs_to :commentable, :polymorphic => true
end

Et un mode ForumTopics:

class ForumTopic < ActiveRecord::Base
  has_many :comments, :as => :commentable
end

J'ai plusieurs autres modèles « commentable » qui ne sont pas importants en ce moment. Tout cela fonctionne.

Ce que je suis en train de faire est de trouver tous les commentaires qui appartiennent à un ForumTopic avec une condition spécifiée (dans ce cas, « en vedette » == true).

Quand j'essaie d'utiliser un viseur pour rejoindre les modèles:

@comments = Comment.find(:all 
            :joins => :commentable
            :conditions => ["forum_topics.featured = ? ", true] 
            )

Je reçois l'erreur suivante:

  

ne peut pas charger avec impatience l'association polymorphique: commentable

Utilisation de l'AR "comprend la syntaxe":

@comments = Comment.find(:all 
            :include => :forum_topics
            :conditions => ["forum_topics.featured = ? ", true] 
            )

renvoie:

  

Association nommée 'forum_topics' n'a pas été trouvé; peut-être vous avez mal orthographié il?

Si je tente et se joindre à un nom de table au lieu du nom d'association (chaîne au lieu de symbole):

@comments = Comment.find(:all,
            :joins => "forum_topics",
            :conditions => ["forum_topics.featured = ? ", true] 
            )

Je vois:

  

Mysql :: Erreur: 'Commentaires' une table inconnue:. SELECT commentaires des commentaires forum_topics OU (forum_topics.featured = 1) *

(Vous pouvez voir ici que la syntaxe de la requête sous-jacente est totalement hors tension et la jointure manque tout à fait).

Je ne sais pas si ce que je fais est même possible, et il y a d'autres façons d'atteindre le résultat recherché, mais il semble que ce devrait faisable.

Toutes les idées? Tout ce que je suis absent?

Était-ce utile?

La solution

Argh!

Je pense avoir trouvé le problème.

Lors de l'assemblage via:

@comments = Comment.find(:all,
        :joins => "forum_topics",
        :conditions => ["forum_topics.featured = ? ", true] 
        )

Vous avez besoin du tout rejoindre!

:joins => "INNER JOIN forum_topics ON forum_topics.id = comments.commentable_id",

Voir la toujours impressionnante: http://guides.rubyonrails.org/active_record_querying.html#joining-tables

Autres conseils

Une vieille question, mais il y a un moyen plus propre d'y parvenir en créant une association directe pour le type spécifique avec le polymorphes:

#comment.rb
class Comment < ActiveRecord::Base

  belongs_to :commentable, polymorphic: true
  belongs_to :forum_topics, -> { where( comments: { commentable_type: 'ForumTopic' } ).includes( :comments ) }, foreign_key: 'commentable_id'

  ...

end

Vous êtes alors en mesure de passer à :forum_topics includes se débarrasser de la nécessité d'un désordre rejoindre:

@comments = Comment
  .includes( :forum_topics )
  .where( :forum_topics => { featured: true } )

Vous pouvez ensuite encore nettoyer ce en déplaçant la requête dans un champ:

#comment.rb
class Comment < ActiveRecord::Base

  ...

  scope :featured_topics, -> { 
    includes( :forum_topics )
    .where( :forum_topics => { featured: true } ) 
  }

  ...

end

Laissant de pouvoir faire simplement

@comments = Comment.featured_topics

Vous avez besoin d'un conditionnel, Grandes rails 3 +

Beaucoup de gens fait allusion dans les réponses et les commentaires, mais je sentais que les gens, y compris moi-même, obtiendraient trébuché si je suis arrivé ici et ne pas lire assez bien.

Alors, voici la bonne réponse, y compris le conditionnel qui est absolument nécessaire.

@comments = Comment.joins( "INNER JOIN forum_topics ON comments.commentable_id = forum_topics.id" )
                   .where( comments:     { commentable_type: 'ForumTopic' } )
                   .where( forum_topics: { featured:         true         } )

Merci à tous, en particulier @Jits, @Peter et @prograils pour leurs commentaires.

La solution retenue ne fonctionne pas une fois que vous introduisez un autre modèle qui a une association avec « commentable ». commentable_id n'est pas unique et donc vous allez commencer à récupérer les mauvais commentaires.

Par exemple:

Vous décidez d'ajouter un modèle de nouvelles qui accepte les commentaires ...

class News < ActiveRecord::Base
   has_many :comments, :as => :commentable
end

Maintenant, vous pouvez obtenir deux enregistrements en arrière si vous avez fait un commentaire sur forum_topic avec un identifiant de 1 et un article de nouvelles avec un identifiant de 1 en utilisant votre requête:

:joins => "INNER JOIN forum_topics ON forum_topics.id = comments.commentable_id"

Vous pourriez probablement résoudre le problème en fournissant un commentable_type comme l'un de vos conditions, mais je ne pense pas que ce soit la meilleure façon d'aborder cette question.

Je suis tombé sur ce poste et il me mène à ma solution. Utilisation de la commentable_type comme l'un de mes conditions mais en utilisant un LEFT OUTER JOIN à la place. Que les sujets du forum façon sans commentaires seront inclus.

LEFT OUTER JOIN `comments` ON `comments`.`commentable_id` = `forum_topics`.`id` AND `comments`.`commentable_type` = 'ForumTopic'

cochés à travailler sous Rails 5 :

Solution 1:

@comments = Comment
              .where(commentable_type: "ForumTopic")
              .joins("INNER JOIN forum_topics ON comments.commentable_id = forum_topics.id")
              .where(forum_topics: {featured: true})
              .all

ou

Solution 2:

@comments = Comment
              .joins("INNER JOIN forum_topics ON comments.commentable_id = forum_topics.id AND comments.commentable_type = 'ForumTopic'")
              .where(forum_topics: {featured: true}).all

Faites attention à la syntaxe SQL brute: pas de contre-apostrophes sont autorisés. Voir http://guides.rubyonrails.org/active_record_querying.html#joining-tables.

Personnellement, je préfère Solution 1 car il contient moins de syntaxe SQL brute.

Rails ne comprend pas polymorphes rejoindre par défaut, mais ce petit bijou vous aiderait à relier votre relation polymorphes avec facilité. https://github.com/jameshuynh/polymorphic_join

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top