Вопрос

Я использую полиморфные ассоциации для отслеживания комментариев в моем проекте.Все очень прямолинейные вещи.

Проблема, с которой я сталкиваюсь, заключается в запросе на основе полиморфной ассоциации и присоединении из модели комментариев обратно к ее владельцу.

Итак ...

У меня есть модель комментария

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

И режим тематических форумов:

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

У меня есть несколько других "комментируемых" моделей, которые сейчас не важны.Все это работает.

То, что я пытаюсь сделать, это найти все комментарии, которые принадлежат теме форума с указанным условием (в данном случае 'featured' == true).

Когда я пытаюсь использовать поисковик, чтобы присоединиться к моделям:

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

Я получаю следующую ошибку:

Не удается с готовностью загрузить полиморфную ассоциацию:комментируемая

Использование AR "включить синтаксис":

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

ВОЗВРАТ:

Ассоциация с именем 'forum_topics' не найдена;возможно, вы неправильно написали это?

Если я попытаюсь объединить с именем таблицы вместо имени ассоциации (строка вместо символа):

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

Я вижу:

Mysql::Ошибка:Неизвестная таблица "комментарии":ВЫБЕРИТЕ комментарии. ИЗ комментариев forum_topics, ГДЕ (forum_topics.featured = 1 )*

(Здесь вы можете видеть, что синтаксис базового запроса полностью отключен, а соединение вообще отсутствует).

Не уверен, возможно ли вообще то, что я делаю, и есть другие способы достичь требуемого результата, но похоже, что это следует быть выполнимым.

Есть какие-нибудь идеи?Чего-нибудь мне не хватает?

Это было полезно?

Решение

Аргх!

Я думаю, что нашел проблему.

При присоединении через:

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

Вам нужно все соединение целиком!

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

Увидеть всегда потрясающее:http://guides.rubyonrails.org/active_record_querying.html#joining-tables

Другие советы

Старый вопрос, но есть более чистый способ достичь этого, установив прямую ассоциацию для определенного типа вместе с полиморфным:

#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

Тогда вы сможете пройти :forum_topics Для includes избавление от необходимости беспорядочного соединения:

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

Затем вы могли бы дополнительно очистить это, переместив запрос в область видимости:

#comment.rb
class Comment < ActiveRecord::Base

  ...

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

  ...

end

Оставляя вам возможность просто делать

@comments = Comment.featured_topics

Вам нужно Условное обозначение, плюс Rails 3+

Многие люди упоминали об этом в ответах и комментариях, но я чувствовал, что люди, включая меня, запутаются, если я попаду сюда и не прочитаю достаточно внимательно.

Итак, вот правильный ответ, включая условие, которое является абсолютно необходимо.

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

Спасибо всем, особенно @Jits, @Peter и @prograils за их комментарии.

Принятое решение не работает, как только вы вводите другую модель, которая имеет ассоциацию с использованием "commentable".commentable_id не уникален, и поэтому вы начнете извлекать неправильные комментарии.

Например:

Вы решили добавить новостную модель, которая принимает комментарии...

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

Теперь вы можете получить две записи обратно, если вы оставили комментарий к forum_topic с идентификатором 1 и новостной статье с идентификатором 1, используя свой запрос:

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

Вероятно, вы могли бы решить проблему, указав commentable_type в качестве одного из ваших условий, но я не думаю, что это лучший способ подойти к этой проблеме.

Я наткнулся на этот пост, и он привел меня к моему решению.Используя commentable_type в качестве одного из моих условий, но вместо этого используя ЛЕВОЕ ВНЕШНЕЕ СОЕДИНЕНИЕ.Таким образом, будут включены темы форума без комментариев.

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

Проверено на работу в соответствии Рельсы 5:

Решение 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

или

Решение 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

Обратите внимание на необработанный синтаксис SQL:отступления не допускаются.Видишь http://guides.rubyonrails.org/active_record_querying.html#joining-tables .

Лично я предпочитаю решение 1, поскольку оно содержит меньше необработанного синтаксиса SQL.

Rails по умолчанию не включает полиморфное соединение, но этот драгоценный камень поможет вам с легкостью объединить ваши полиморфные отношения. https://github.com/jameshuynh/polymorphic_join

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top