为什么 Postgres 不接受我的计数列?

克里斯托弗·赖尔

我正在构建一个具有以下模型的 Rails 应用程序:

# vote.rb
class Vote < ApplicationRecord
  belongs_to :person
  belongs_to :show
  scope :fulfilled, -> { where(fulfilled: true) }
  scope :unfulfilled, -> { where(fulfilled: false) }
end

# person.rb
class Person < ApplicationRecord
  has_many :votes, dependent: :destroy

  def self.order_by_votes(show = nil)
    count = 'nullif(votes.fulfilled, true)'
    count = "case when votes.show_id = #{show.id} AND NOT votes.fulfilled then 1 else null end" if show
    people = left_joins(:votes).group(:id).uniq!(:group)
    people = people.select("people.*, COUNT(#{count}) AS people.vote_count")
    people.order('people.vote_count DESC')
  end
end

背后的想法order_by_votesPeople按未完成的票数排序,要么计算所有选票,要么只计算与给定Show.

当我针对 SQLite 进行测试时,这似乎工作正常。但是当我切换到 Postgres 时,我收到此错误:

Error:
PeopleControllerIndexTest#test_should_get_previously_on_show:
ActiveRecord::StatementInvalid: PG::UndefinedColumn: ERROR:  column people.vote_count does not exist
LINE 1: ...s"."show_id" = $1 GROUP BY "people"."id" ORDER BY people.vot...
                                                             ^

如果我使用 转储 SQL @people.to_sql,这就是我得到的:

SELECT people.*, COUNT(nullif(votes.fulfilled, true)) AS people.vote_count FROM "people" LEFT OUTER JOIN "votes" ON "votes"."person_id" = "people"."id" GROUP BY "people "."id" ORDER BY people.vote_count DESC

为什么这在 Postgres 上失败,但在 SQLite 上工作?我应该怎么做才能让它在 Postgres 上工作?

(PS:我people.vote_count用一个点命名了该字段,所以我可以在我的视图中访问它而无需执行另一个 SQL 查询来实际查看视图中每个人的投票计数(不确定这是否有效)但我得到了即使我简单地命名该字段,也会出现同样的错误vote_count。)

(PS2:我最近添加了.uniq!(:group)因为 Rails 6.2 的一些弃用警告,但我找不到任何文档,所以我不确定我做对了,如果没有那部分,错误仍然存​​在。)

克里斯托弗·赖尔

感谢所有的评论和答案,我终于找到了一个解决方案,我认为这是解决这个问题的最佳方法。

首先,当我调用pagy它试图通过附加.count(:all). 这就是导致错误的原因。解决方案是不在中创建“字段”select()并在.order().

所以这是正确的代码:

def self.order_by_votes(show = nil)
  count = if show
            "case when votes.show_id = #{show.id} AND NOT votes.fulfilled then 1 else null end"
          else
            'nullif(votes.fulfilled, true)'
          end
  left_joins(:votes).group(:id)
                    .uniq!(:group)
                    .select("people.*, COUNT(#{count}) as vote_count")
                    .order(Arel.sql("COUNT(#{count}) DESC"))
end

这根据未完成的投票数对人数进行排序,能够仅计算给定节目的投票数,并且它适用于pagy()pagy_arel()在我的情况下更适合,因此可以正确地对结果进行分页.

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章