ruby - Rails+ActiveAdmin - 使用 ransacker 过滤会抛出错误 PG::SyntaxError: ERROR: syntax error at or near ","

标签 ruby postgresql ruby-on-rails-4 activeadmin ransack

我在 Ruby on Rails 4.1.4 上有一个项目,使用来自 git://github.com/activeadmin/activeadmin 的 activeadmin 1.0.0.prepg 0.17.1,PostgreSQL 9.3

在项目中我有这些模型:

  1. 类用户 has_one:账户

  2. 类账户 属于:用户 有很多:project_accounts has_many :项目, :through => :project_accounts

  3. 类项目 # 该项目有一个 bool 属性 'archive' has_many :project_accounts

  4. 类 ProjectAccount 属于:帐户 属于:项目

我有一个任务是在索引页面上实现一个名为“by_active_projects”的 ActiveAdmin 过滤器,因此它必须向用户显示已定义数量的事件项目,这意味着此类项目具有 archive = =假。 例如。如果我在过滤器中输入“2”,它必须找到恰好有 2 个事件项目的帐户。

现在我已经在 ActiveAdmin 中注册了“帐户”资源,并且在 admin/account.rb 中我添加了 filter :by_active_projects_eq

之后,我为帐户模型 (models/account.rb) 定义了范围having_active_projects:

scope :having_active_projects, ->(number) { joins(:projects).where("projects.archive = ?", false).having("count(projects) = ?", number).group("accounts.id") }

下一步,我为这样的帐户模型定义了一个掠夺者:

ransacker :by_active_projects, formatter: proc{ |v|
    data = Account.having_active_projects(v).map(&:id)
    data ||= nil
  } do |parent|
    parent.table[:id]
  end

在开发数据库中有一个帐户,正好有 8 个事件项目,过滤非常适合它。但是当我尝试按 2 个事件项目过滤帐户时,我遇到了错误。在数据库中有三个这样的帐户,错误页面报告我查询语法错误:

SELECT COUNT(count_column) FROM (SELECT 1 AS count_column FROM "accounts" WHERE "accounts"."deleted_at" IS NULL AND "accounts"."id" = 'e4d247ec-e64d-4e8a-996a-4d73ccb11257', 'bcb8fa61-4a53-4b45-8954-8fb6ae328365', '93d670b6-7b8f-4c27-91cc-e0f44c137114' LIMIT 30 OFFSET 0) subquery_for_count

如你所见,而不是

"accounts"."id" IN ('e4d247ec-e64d-4e8a-996a-4d73ccb11257', 'bcb8fa61-4a53-4b45-8954-8fb6ae328365', '93d670b6-7b8f-4c27-91cc-e0f44c137114')

正在生成这个东西:

"accounts"."id" = 'e4d247ec-e64d-4e8a-996a-4d73ccb11257', 'bcb8fa61-4a53-4b45-8954-8fb6ae328365', '93d670b6-7b8f-4c27-91cc-e0f44c137114'

我试图深入研究源代码,在 ActiveRecord、ActiveAdmin 和 Ransack 库中的代码片段上移动断点,并发现关系是在 Arel 的帮助下构建的: :Nodes::Equality。我不确定这是不是原因,但我可以肯定地说:

lib/active_record/relation/query_methods.rb `

560   def where!(opts = :chain, *rest)
561      if opts == :chain
562        WhereChain.new(self)
563      else
564        references!(PredicateBuilder.references(opts)) if Hash === opts
565        self.where_values += build_where(opts, rest)
566        self
567      end
568    end`

self 这里是 Account 的 Active Record 关系;

在第 565 行调用 build_where 之前,self.to_sql 等于

SELECT "accounts".* FROM "accounts"  WHERE "accounts"."deleted_at" IS NULL  ORDER BY "accounts"."created_at" desc

在调用它并将结果分配给 self.where_values 之后,

self.to_sql 等于

SELECT "accounts".* FROM "accounts"  WHERE "accounts"."deleted_at" IS NULL AND "accounts"."id" = 'e4d247ec-e64d-4e8a-996a-4d73ccb11257', 'bcb8fa61-4a53-4b45-8954-8fb6ae328365', '93d670b6-7b8f-4c27-91cc-e0f44c137114'  ORDER BY "accounts"."created_at" desc

如有任何帮助或信息,我们将不胜感激!谢谢!

最佳答案

所以我找到了解决方案:

首先,我更改了 admin/account.rb 中的过滤器

filter :by_active_projects_eq

filter :by_active_projects_in,
         :as => :string

这种方法导致了正确的 SQL 生成,

"accounts"."id" IN ('e4d247ec-e64d-4e8a-996a-4d73ccb11257', 'bcb8fa61-4a53-4b45-8954-8fb6ae328365', '93d670b6-7b8f-4c27-91cc-e0f44c137114')

在那之后我也不得不改变我的掠夺者

ransacker :by_active_projects, formatter: proc{ |v|
    data = Account.having_active_projects(v).map(&:id)
    data ||= nil
  } do |parent|
    parent.table[:id]
  end

ransacker :by_active_projects, formatter: proc{ |v|
    data = Account.having_active_projects(v).pluck(:id)
    data.present? ? data : nil
  } do |parent|
    parent.table[:id]
  end

因为它的实现方式也导致了不正确的查询:例如,没有这样的帐户恰好有 5 个事件项目。在那种情况下

data = Account.having_active_projects(v).pluck(:id)

返回“空数组”,并使用data ||= nil 处理此数组实际上从未返回nil,这导致 SQL 如下所示:

SELECT COUNT(count_column) FROM (SELECT  1 AS count_column FROM "accounts"  WHERE "accounts"."deleted_at" IS NULL AND "accounts"."id" IN () LIMIT 30 OFFSET 0) subquery_for_count

注意 "accounts"."id"IN () 部分,它引起了麻烦。

data.present 替换 data ||= nil 之后? ? data : nil,如果 data 不存在,它会被分配一个 nil,SQL 中的那部分是正确生成的:“accounts”。 id"IN (NULL)

关于ruby - Rails+ActiveAdmin - 使用 ransacker 过滤会抛出错误 PG::SyntaxError: ERROR: syntax error at or near ",",我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27094572/

相关文章:

c# - Npgsql EntitiyFramework 无法将记录添加到只有一个整数作为主键的表中

ruby-on-rails - 如何使用 Minitest 测试交互器管理器

sql - 在 PostgreSql 中计算百分比

ruby-on-rails - Rails4 生产 elasticsearch 错误 - 找不到 geo_point,但在开发中有效

ruby-on-rails - rails 4 -- 闪光通知

ruby - 在组织内共享 ruby​​ 代码

ruby - 使用 Zlib for gzip 在 ruby​​ 中压缩大文件

ruby - 在 Ruby CSV 中,如何将空白 , 而不是 ,""写入文件?

ruby-on-rails - 如何在 acts_as_votable 中提取投票最高的模型实例?

postgresql - boolean 值与 PostgreSQL 不一致