Ransack,Postgres - 根据具有distinct:true的关联表列进行排序

8

我有一个应用程序,使用Ransack gem,并且我正在将其从Mysql转换为Postgres。

如果排序列来自关联表并且distinct选项设置为true,则在这种情况下,Postgres会抛出以下错误:

PG::InvalidColumnReference: ERROR:  for SELECT DISTINCT, ORDER BY expressions must appear in select list

Ransack的Github页面上说,在这种情况下,“你需要自己解决问题”。

处理这种情况的最佳策略是什么?

q = Contact.includes(:contact_type).search
q.sorts = ['contact_type_name asc']
q.result(distinct: true)
PG::InvalidColumnReference: ERROR:  for SELECT DISTINCT, ORDER BY expressions must appear in select list

谢谢!

3个回答

10

有一种更简单的方法来解决这个问题。使用ActiveRecord的连接查询或选择查询添加所需的列,例如:

q = Contact.search
q.sorts = ['contact_type_name asc']
q.result(distinct: true).
  includes(:contact_type).
  joins(:contact_type)

或者,如果您只想选择几列,可以执行以下操作:

q = Contact.search
q.sorts = ['contact_type_name asc']
q.result(distinct: true).
  select('contacts.*, contact_type.name')

我已经提交了一个拉取请求,用于更新 Ransack 的自述文件。pull request


谢谢。如果除了这个排序之外,我还要使用另一个属性搜索contact_type,会发生什么情况?我会得到以下错误:缺少表的FROM子句条目。我该如何解决这个问题? - ShivamD
即使五年后,您仍然让人们节省了数百小时的工作时间。谢谢。 - Onur Şahindur

3
我刚遇到了同样的问题,一个快速而不完美的解决方法是添加一个初始化器,适用于单列排序。这个猴子补丁将缺失的排序列添加到选择语句中。
module Ransack
  module Adapters
    module ActiveRecord
      class Context < ::Ransack::Context
        def evaluate(search, opts = {})
          viz = Visitor.new
          relation = @object.where(viz.accept(search.base))
          if search.sorts.any?
            _vaccept = viz.accept(search.sorts)
            table  = _vaccept.first.expr.relation.name
            column = _vaccept.first.expr.name
            relation = relation.except(:order).reorder(_vaccept).select("#{@default_table.name}.*, #{table}.#{column}")
          end
          opts[:distinct] ? relation.distinct : relation
        end
      end
    end
  end
end

如果我添加这个修复,当我尝试对结果进行分页时,会出现"NoMethodError - undefined method `paginate' for #Arel::Nodes::Distinct:0xa3a0ebc"的错误。 - Danny
如果我用relation.uniq替换relation.distinct,一切似乎都可以正常工作...(Rails 3.2) - Danny
我只是把它放进去,然后它就工作了。Rails 4.2.6。谢谢Eren!你应该提交一个PR。 - brendan

0

其中一个解决方法:

class Contact < ApplicationRecord
   belongs_to :contact_type
   scope :sort_by_contact_type_name_asc, lambda { select('contacts.*, contact_types.name').left_joins(:contact_type).order(СontactType.arel_table[:name].asc) }
   scope :sort_by_contact_type_name_desc, lambda { select('contacts.*, contact_types.name').left_joins(:contact_type).order(СontactType.arel_table[:name].desc) }
end
 
q = Contact.search
q.sorts = ['contact_type_name asc']
q.result(distinct: true)

来源:

https://github.com/activerecord-hackery/ransack/issues/429 https://activerecord-hackery.github.io/ransack/getting-started/simple-mode/#:~:text=class%20Person%20%3C%20ActiveRecord%3A%3ABase


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接