我正在使用多态关联来跟踪我的项目中的注释。所有非常直接的东西。
我遇到的问题是基于多态关联查询并从Comment模型加入到它的所有者。
所以......
我有一个评论模型
class Comment < ActiveRecord::Base
belongs_to :commentable, :polymorphic => true
end
和ForumTopics模式:
class ForumTopic < ActiveRecord::Base
has_many :comments, :as => :commentable
end
我还有其他几个“可评论”的模型,现在并不重要。所有这一切都有效。
我想要做的是找到属于具有指定条件的ForumTopic的所有注释(在这种情况下,'featured'== true)。
当我尝试使用finder加入模型时:
@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 ::错误:未知表'comments':SELECT注释。 FROM comments forum_topics WHERE(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
一旦引入另一个使用“可评论”关联的模型,接受的解决方案就不起作用。 commentable_id不是唯一的,因此您将开始检索错误的注释。
例如:
您决定添加接受评论的新闻模型......
class News < ActiveRecord::Base
has_many :comments, :as => :commentable
end
现在,如果您对id为1的forum_topic和使用您的查询的ID为1的新闻文章发表评论,您可能会收到两条记录:
:joins => "INNER JOIN forum_topics ON forum_topics.id = comments.commentable_id"
您可以通过提供commentable_type作为您的条件之一来解决问题,但我认为这不是解决此问题的最佳方法。
许多人在答案和评论中提到了它,但我觉得,如果我在这里登陆并且阅读不够彻底,包括我在内的人会被绊倒。
所以,这是正确的答案,包括绝对必要的条件。
@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_type作为我的条件之一,但使用LEFT OUTER JOIN代替。这样,将包含没有评论的论坛主题。
LEFT OUTER JOIN `comments` ON `comments`.`commentable_id` = `forum_topics`.`id` AND `comments`.`commentable_type` = 'ForumTopic'
检查在Rails 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默认情况下不包含多态连接,但是这个gem可以帮助您轻松加入多态关系。 https://github.com/jameshuynh/polymorphic_join