Pregunta

Estoy utilizando asociaciones polimórficas para rastrear Comentarios en mi proyecto. Todo esto es muy muy directa.

El problema que tengo es en la consulta sobre la base de la asociación polimórfica y uniéndose a partir del modelo de comentario de nuevo a su propietario.

Así que ...

Tengo un modelo de comentario

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

Y un modo de ForumTopics:

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

Tengo varios otros modelos "commentable" que no son importantes en este momento. Todo esto funciona.

Lo que estoy tratando de hacer es encontrar todos los Comentarios que pertenecen a un ForumTopic con una condición especificada (en este caso, 'ofrecido' == true).

Cuando intento y utilizar un buscador para unirse a los modelos:

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

recibo el siguiente error:

  

puede no cargar con entusiasmo la asociación polimórfica: commentable

Uso de la AR "incluyen sintaxis":

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

retornos:

  

No se encontró asociación con nombre '' forum_topics; tal vez mal escrito que?

Si lo intento y me uno con un nombre de tabla en lugar del nombre de la asociación (cadena en lugar de símbolo):

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

veo:

  

MySQL :: error: 'comentarios' Desconocido tabla:. SELECT comentarios DESDE DONDE comentarios forum_topics (forum_topics.featured = 1) *

(Se puede ver aquí que la sintaxis de la consulta subyacente es totalmente apagado y la unión no se encuentra en total).

No estoy seguro si lo que estoy haciendo es incluso posible, y hay otras maneras de lograr el resultado deseado, pero parece que debe sea factible.

¿Alguna idea? Cualquier cosa que me falta?

¿Fue útil?

Solución

Argh!

Creo que he encontrado el problema.

Cuando se unen a través de:

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

Es necesario el conjunto unirse!

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

Vea la siempre impresionante: http://guides.rubyonrails.org/active_record_querying.html#joining-tables

Otros consejos

Una cuestión de edad, pero hay una forma más limpia de lograr esto mediante la creación de una asociación directa para el tipo específico junto con el polimórfico:

#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

Que luego son capaces de pasar a :forum_topics includes deshacerse de la necesidad de un desordenado unirse a:

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

A continuación, podría limpiar aún más este movimiento por la consulta en un ámbito de aplicación:

#comment.rb
class Comment < ActiveRecord::Base

  ...

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

  ...

end

Dejando que sea capaz de hacer simplemente

@comments = Comment.featured_topics

¿Necesita un condicional, rieles Plus 3 +

Una gran cantidad de personas que se alude a ella en las respuestas y comentarios, pero sentí que la gente, incluido yo mismo, conseguirían tropezar si aterricé aquí y no haber leído a fondo suficiente.

Por lo tanto, aquí está la respuesta correcta, incluyendo el condicional es decir absolutamente es necesario.

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

Gracias a todos, especialmente @Jits, @Peter y @prograils por sus comentarios.

La solución aceptada no funciona una vez que se introduce otro modelo que tiene una asociación usando "commentable". commentable_id no es única y por lo tanto se va a empezar a recuperar los comentarios equivocados.

Por ejemplo:

Se decide agregar un modelo de prensa que acepta los comentarios ...

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

Ahora es posible obtener dos registros de regreso si ha realizado un comentario en un forum_topic con un ID de 1 y un artículo de noticias con un id de 1 utilizando su consulta:

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

Probablemente se podría resolver el problema mediante el suministro de un commentable_type como uno de sus condiciones, pero no creo que esa es la mejor manera de abordar este problema.

Me encontré con este post y me llevo a mi solución. Utilizando el commentable_type como una de mis condiciones, pero utilizando una combinación externa izquierda en su lugar. Se incluirán los temas en los que camino sin comentarios.

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

A cuadros para trabajar bajo Rails 5 :

Solución 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

o

Solución 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

Prestar atención a la sintaxis SQL prima: no hay acentos abiertos están permitidos. Ver http://guides.rubyonrails.org/active_record_querying.html#joining-tables.

Yo personalmente prefiero la solución 1, ya que contiene menos de sintaxis SQL prima.

Carriles no incluye un polimorfo se unen por defecto, pero esta joya le ayudaría a se une a su relación polimórfica con facilidad. https://github.com/jameshuynh/polymorphic_join

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top