ruby-on-rails - 组合包含连接和分组的范围
问题描述
我正在寻找一个 DRY 解决方案来解决在 Rails 中组合两个或多个包含不同连接和分组的范围的问题。我有一个带有::with_authors
范围的评论模型(以防止在引用作者姓名时出现 N+1),如下所示:
# comment.rb
scope :with_authors, -> do
select("comments.*, users.username AS author_name")
.joins(:author)
end
而且我对允许评论和其他模型从用户那里获得投票的多态关联有一个“可投票”的关注。这包括::with_votes
如下范围:
# votable.rb
scope :with_votes, -> do
select( "#{self.table_name}.*, COALESCE(SUM(votes.value), 0) AS vote_sum" )
.left_joins(:votes)
.group("#{self.table_name}.id")
end
两个范围都需要显示带有作者姓名和收到的投票数的评论列表。但是将两者结合起来,post.comments.with_authors.with_votes会导致熟悉的错误:
> PG::GroupingError: ERROR: column "users.username" must appear in the
> GROUP BY clause or be used in an aggregate function
我意识到我可以编写一个单独的范围来执行连接并相应地更改分组,但这不能转移到支持投票的其他模型,并且违反了每个方法或范围应该做一件事的原则。我也尝试使用合并 - post.comments.with_authors.merge( post.comments.with_votes ) - 但这给出了同样的错误。有没有办法编写一个或两个范围,以便它们一起工作,但它们也可以单独使用,同时确保 ::with_votes 适用于使用可投票关联的其他模型?非常感谢期待!
解决方案
一种方法是使用子查询而不是将分组应用于基本查询。例如:
scope :with_votes, -> do
select( <<~SQL )
(
SELECT COUNT(*)
FROM votes
WHERE votable_type = '#{self.class.name}' AND
votable_id = '#{self.table_name}.id'
) AS votes
SQL
end
推荐阅读
- javascript - setInterval 不适用于 file_get_contents
- active-directory - 如何在 Hashicorp Vault 中对成员资格搜索进行分组
- mysql - Mysql 服务器未启动错误 13 Ubuntu 20.04
- memory-management - 虚拟机怎么写?
- java - 在 FileNET/CMIS Web 服务中调用 getContentStream() 函数
- amazon-s3 - Magento 2.4.2-p1 使用媒体存储云 AWS S3 存储桶 - 未生成缓存图像
- flutter - Flutter中的ListTile开关如何单独改变按钮的形状和大小
- db2 - IBM 云上的免费 db2 实例在重新激活后不可用
- javascript - 带有 JSON 正文的 GET 请求
- math - 虚数和负面积