ruby on rails - form_with - ActiveRecord-consulta de asociaciones polimórficas
rails form_tag (6)
Necesita un Condicional, Plus Rails 3+
Mucha gente aludió a esto en las respuestas y comentarios, pero sentí que las personas, incluyéndome a mí, se verían frustradas si aterrizaba aquí y no leía lo suficiente.
Entonces, aquí está la respuesta correcta, incluido el condicional que es absolutamente 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 } )
Rails 5+
Para Rails 5+, necesita eliminar los ticks traseros en la cadena de consulta:
@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 a @Jits, @Peter y @prograils por sus comentarios.
Estoy usando asociaciones polimórficas para rastrear Comentarios en mi proyecto. Todo muy sencillo.
El problema que tengo es consultar en función de la asociación polimórfica y unirme desde el modelo de comentarios a su propietario.
Asi que ...
Tengo un modelo de comentario
class Comment < ActiveRecord::Base
belongs_to :commentable, :polymorphic => true
end
Y un modo ForumTopics:
class ForumTopic < ActiveRecord::Base
has_many :comments, :as => :commentable
end
Tengo varios otros modelos "commentables" que no son importantes en este momento. Todo esto funciona
Lo que intento hacer es encontrar todos los comentarios que pertenecen a ForumTopic con una condición especificada (en este caso, ''featured'' == true).
Cuando intento usar un buscador para unirme a los modelos:
@comments = Comment.find(:all
:joins => :commentable
:conditions => ["forum_topics.featured = ? ", true]
)
Recibo el siguiente error:
No puedo cargar con entusiasmo la asociación polimórfica: commentable
Usando AR "include syntax":
@comments = Comment.find(:all
:include => :forum_topics
:conditions => ["forum_topics.featured = ? ", true]
)
devoluciones:
La asociación llamada ''forum_topics'' no se encontró; tal vez lo deletreaste mal?
Si intento unirme a un nombre de tabla en lugar del nombre de asociación (cadena en lugar de símbolo):
@comments = Comment.find(:all,
:joins => "forum_topics",
:conditions => ["forum_topics.featured = ? ", true]
)
Ya veo:
Mysql :: Error: tabla desconocida ''comentarios'': SELECCIONAR comentarios. DE LOS COMENTARIOS forum_topics DONDE (forum_topics.featured = 1) *
(Puede ver aquí que la sintaxis de la consulta subyacente está totalmente desactivada y la combinación falta por completo).
No estoy seguro si lo que estoy haciendo es incluso posible, y hay otras maneras de lograr el resultado requerido, pero parece que debería ser factible.
¿Algunas ideas? ¿Algo que me falta?
Argh!
Creo que encontré el problema.
Cuando se une a través de:
@comments = Comment.find(:all,
:joins => "forum_topics",
:conditions => ["forum_topics.featured = ? ", true]
)
¡Necesitas la unión completa!
:joins => "INNER JOIN forum_topics ON forum_topics.id = comments.commentable_id",
Mira lo maravilloso: http://guides.rubyonrails.org/active_record_querying.html#joining-tables
Comprobado para trabajar en 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
Preste atención a la sintaxis SQL sin procesar: no se permiten los trazos inversos. Ver http://guides.rubyonrails.org/active_record_querying.html#joining-tables .
Personalmente prefiero la Solución 1, ya que contiene menos sintaxis de SQL sin formato.
Encontré esta publicación y me llevó a mi solución. Usar el tipo commentable_ como una de mis condiciones, pero usando un LEFT OUTER JOIN en su lugar. De esa forma se incluirán los temas del foro sin comentarios.
LEFT OUTER JOIN `comments` ON `comments`.`commentable_id` = `forum_topics`.`id` AND `comments`.`commentable_type` = ''ForumTopic''
La solución aceptada no funciona una vez que introduce otro modelo que tiene una asociación que usa "commentable". commentable_id no es único y, por lo tanto, comenzará a recuperar los comentarios incorrectos.
Por ejemplo:
Usted decide agregar un modelo de noticias que acepta comentarios ...
class News < ActiveRecord::Base
has_many :comments, :as => :commentable
end
Ahora puede recuperar dos registros si realizó un comentario en un forum_topic con una identificación de 1 y un artículo de noticias con una identificación de 1 usando su consulta:
:joins => "INNER JOIN forum_topics ON forum_topics.id = comments.commentable_id"
Probablemente puedas resolver el problema suministrando un tipo commentable_ como una de tus condiciones, pero no creo que sea la mejor manera de abordar este problema.
Una vieja pregunta, pero hay una manera más clara de lograr esto al configurar 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
A continuación, puede aprobar :forum_topics
para includes
eliminación de la necesidad de una unión desordenada:
@comments = Comment
.includes( :forum_topics )
.where( :forum_topics => { featured: true } )
Luego puede limpiar esto moviendo la consulta a un alcance:
#comment.rb
class Comment < ActiveRecord::Base
...
scope :featured_topics, -> {
includes( :forum_topics )
.where( :forum_topics => { featured: true } )
}
...
end
Dejándolo para poder simplemente hacer
@comments = Comment.featured_topics