繁体   English   中英

组合包含连接和分组的范围

[英]Combining scopes that contain joins and groupings

我正在寻找一个 DRY 解决方案来解决在 Rails 中组合两个或多个包含不同连接和分组的范围的问题。 我有一条评论 model 和::with_authors scope (以防止在引用作者姓名时出现 N+1),如下所示:

# comment.rb
scope :with_authors, -> do
  select("comments.*, users.username AS author_name")
  .joins(:author)
end

而且我对允许评论和其他模型从用户那里获得投票的多态关联有一个“可投票”的关注。 这包括::with_votes scope 如下:

# 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

我意识到我可以编写一个 scope 来执行连接并相应地更改分组,但这不能转移到支持投票的其他模型,并且违反了每种方法或 scope 应该做一件事的原则。 我也尝试使用合并 - 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

我发现为了防止 group_by 错误,您可以简单地将包含所需附加字段的附加group语句链接到预定义的 scope 或查询。 就我而言,这意味着更少的代码重复,我最终定义了如下注释 scope,确保封装了附加的 group 语句:

scope :with_votes_and_authors, -> do
  with_authors.with_votes.group("users.username")
end

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM