Rails Active Admin中Scope触发PG::InvalidColumnReference错误求助
问题根源分析
这个错误的核心原因是PostgreSQL对DISTINCT ON的严格约束:使用DISTINCT ON时,ORDER BY子句的第一个字段必须和DISTINCT ON指定的字段完全一致。
你在控制台调用Scope时正常,是因为控制台没有额外添加排序条件;但Active Admin默认会给所有查询追加一个ORDER BY "email_stats"."id" desc的排序规则,这就导致最终生成的SQL里,ORDER BY的第一个字段变成了id,而非你Scope里指定的clicked_url,直接违反了PostgreSQL的规则,所以抛出了错误。
解决方案
最直接的修复方式是把Scope里的order替换成reorder,reorder会完全覆盖现有的排序规则,而不是像order那样追加:
scope :clicked, -> { select('distinct on (email_stats.clicked_url) email_stats.*').reorder(:clicked_url, :action_performed_at) }
为什么这能解决问题?
order方法是在现有排序基础上追加新的排序条件,所以Active Admin的默认ORDER BY id desc会保留在最前面,导致排序顺序不符合DISTINCT ON要求。reorder方法会直接替换掉所有已有的排序规则,最终生成的SQL里,ORDER BY的第一个字段就是clicked_url,完全符合PostgreSQL的DISTINCT ON约束。
备选方案(按需保留默认排序逻辑)
如果你想在其他Scope里保留Active Admin的默认排序,只针对clicked Scope修改,可以在Active Admin的资源配置里单独处理:
ActiveAdmin.register EmailStat do scope :clicked do |collection| collection.select('distinct on (email_stats.clicked_url) email_stats.*').reorder(:clicked_url, :action_performed_at) end # 或者通过控制器钩子覆盖排序逻辑 controller do def apply_scopes(chain) if params[:scope] == 'clicked' chain.reorder(:clicked_url, :action_performed_at) else super end end end end
这样只有当用户选中clicked Scope时,才会替换排序规则,其他Scope不受影响。
内容的提问来源于stack exchange,提问作者Shairyar
相关产品推荐
相关产品推荐

