Pergunta

Eu estou usando associações polimórficas para acompanhar comentários no meu projeto. Todas as coisas muito para a frente.

O problema que tenho é em consulta com base na associação polimórfica e juntando-se a partir do Comentário modelo de volta a ele é proprietário.

Então ...

Eu tenho um modelo Comment

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

E um modo ForumTopics:

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

Eu tenho vários outros modelos "commentable" que não são importantes agora. Tudo isso funciona.

O que estou tentando fazer é encontrar todos os Comentários que pertencem a um ForumTopic com uma condição especificada (neste caso, 'destaque' == true).

Quando tento usar um localizador para juntar os modelos:

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

Eu recebo o seguinte erro:

não pode ansiosamente carregar a associação polimórfica: commentable

Usando a AR "incluem sintaxe":

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

retornos:

associação denominada 'forum_topics' não foi encontrado; talvez você grafada-lo?

Se eu tentar e juntar-se com um nome de tabela em vez do nome de associação (string em vez de símbolo):

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

Eu vejo:

Mysql :: Erro: tabela desconhecido 'comentários':. Observações Select dos comentários forum_topics WHERE (forum_topics.featured = 1) *

(Você pode ver aqui que a sintaxe da consulta subjacente é totalmente fora e a junção está faltando completamente).

Não tenho certeza se o que eu estou fazendo é mesmo possível, e há outras maneiras de conseguir o resultado necessário, mas parece que ele deve ser factível.

Todas as idéias? Qualquer coisa que eu estou ausente?

Foi útil?

Solução

Argh!

Eu acho que encontrei o problema.

Ao aderir via:

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

Você precisa se juntar ao todo!

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

Veja a sempre impressionante: http://guides.rubyonrails.org/active_record_querying.html#joining-tables

Outras dicas

Uma questão de idade, mas há uma maneira mais limpa de conseguir isso através da criação de uma associação direta para o tipo específico juntamente com o polimórfica:

#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

Está, então, capaz de passar :forum_topics para includes livrar-se da necessidade de um confuso juntar-se:

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

Você poderia, então, limpar ainda mais esta se movendo a consulta em um escopo:

#comment.rb
class Comment < ActiveRecord::Base

  ...

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

  ...

end

Deixando-o de ser capaz de simplesmente fazer

@comments = Comment.featured_topics

Você precisa de um condicional, Além disso, o Rails 3 +

Um monte de pessoas aludidas-lo nas respostas e comentários, mas eu senti que as pessoas, inclusive eu, iria tropeçar se eu desembarcou aqui e não ler cuidadosamente o suficiente.

Então, aqui está a resposta adequada, incluindo a condicional que é absolutamente necessário.

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

Obrigado a todos, especialmente @Jits, @ Pedro, e @prograils para seus comentários.

A solução aceita não funciona uma vez que você introduzir um outro modelo que tem uma associação usando "commentable". commentable_id não é única e, portanto, você vai começar a recuperar os comentários erradas.

Por exemplo:

Você decide adicionar um modelo notícia de que aceita comentários ...

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

Agora você pode obter dois registros de volta se você fez um comentário sobre um forum_topic com um ID de 1 e uma notícia com um id 1 usando sua consulta:

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

Você provavelmente poderia resolver o problema fornecendo um commentable_type como uma das suas condições, mas eu não acho que é a melhor maneira de abordar esta questão.

me deparei com este post e me levar a minha solução. Usando o commentable_type como uma das minhas condições, mas usando um LEFT OUTER JOIN em vez. Que tópicos do fórum maneira sem comentários serão incluídos.

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

verificado ao trabalho sob Trilhos 5 :

Solução 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

Solução 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 atenção à sintaxe SQL RAW: No backticks são permitidos. Consulte http://guides.rubyonrails.org/active_record_querying.html#joining-tables.

Eu pessoalmente prefiro Solução 1, uma vez que contém menos sintaxe SQL cru.

Rails não inclui um polimórfico se juntar por padrão, mas esta jóia iria ajudá-lo a se junta o seu relacionamento polimórfico com facilidade. https://github.com/jameshuynh/polymorphic_join

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top