2014-11-23 38 views
6

我对Ruby的项目on Rails的4.1.4,使用activeadmin 1.0.0.pre from git://github.com/activeadmin/activeadminpg 0.17.1,PostgreSQL的9.3的Rails + ActiveAdmin - 与ransacker过滤抛出Error PG ::语法错误:错误:语法错误或接近 “”

在项目中,我有这些模型:

  1. class User has_one :account

  2. class Account belongs_to :user has_many :project_accounts has_many :projects, :through => :project_accounts

  3. class Project # the project has a boolean attribute 'archive' has_many :project_accounts

  4. class ProjectAccount belongs_to :account belongs_to :project

我已经得到落实的索引页,名为“by_active_projects”上ActiveAdmin过滤器的任务,所以它必须证明已定义的活跃号码的用户项目,这意味着这样的项目有archive == false。 例如如果我在筛选器中键入'2',则必须找到具有2个活动项目的帐户。

对于ActiveAdmin现在我已经注册了“户口”的资源,并在admin/account.rb我添加filter :by_active_projects_eq

后,我已经定义了一个范围having_active_projects的帐户模型(模型/ account.rb):

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

下一步,我定义为帐户模型ransacker这样的:

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

在发展DB有一个帐户,该帐户恰好有8个活动项目,过滤对此非常有用。但是当我试图通过2个活动项目筛选帐户时,我遇到了一个错误。在DB有三个这样的账户,并错误页面报道我,查询语法错误:不是

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

正在生成这个东西

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" = '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这里是一个账户活动记录关系;

在列#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 

任何帮助或有关这个问题的信息表示赞赏!谢谢!

回答

4

所以我找到了解决办法:

首先,我改变了我的过滤器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从

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()的一部分,这是制造麻烦。 "accounts"."id" IN (NULL)

data.present? ? data : nil替换data ||= nil,如果data不存在它被分配一个nil,并被corectly生成SQL那部分之后

相关问题