Ruby on rails 阿雷尔+;Rails 4.2导致问题(绑定丢失)

Ruby on rails 阿雷尔+;Rails 4.2导致问题(绑定丢失),ruby-on-rails,ruby,activerecord,arel,Ruby On Rails,Ruby,Activerecord,Arel,我们最近从Rails 4.1升级到Rails 4.2,并且发现使用Arel+Activerecord时出现问题,因为我们遇到了这种类型的错误: ActiveRecord::StatementInvalid: PG::ProtocolViolation: ERROR: bind message supplies 0 parameters, but prepared statement "" requires 8 以下是正在破坏的代码: customers = Customer.arel_tab

我们最近从Rails 4.1升级到Rails 4.2,并且发现使用Arel+Activerecord时出现问题,因为我们遇到了这种类型的错误:

ActiveRecord::StatementInvalid: PG::ProtocolViolation: ERROR:  bind message supplies 0 parameters, but prepared statement "" requires 8
以下是正在破坏的代码:

customers = Customer.arel_table

      ne_subquery = ImportLog.where(
        importable_type: Customer.to_s,
        importable_id: customers['id'],
        remote_type: remote_type.to_s.singularize,
        destination: 'hello'
      ).exists.not

      first  = Customer.where(ne_subquery).where(company_id: @company.id)
      second = Customer.joins(:import_logs).merge(
        ImportLog.where(
          importable_type: Customer.to_s,
          importable_id: customers['id'],
          remote_type: remote_type.to_s.singularize,
          status: 'pending',
          destination: 'hello',
          remote_id: nil
        )
      ).where(company_id: @company.id)

      Customer.from(
        customers.create_table_alias(
          first.union(second),
          Customer.table_name
        )
      )
我们找到了如何通过将exists.not移动到Customer中来解决查询的第一部分(遇到了相同的rails错误,即没有绑定),其中:

ne_subquery = ImportLog.where(
       importable_type: Customer.to_s,
       importable_id: customers['id'],
       destination: 'hello'
     )

     first  = Customer.where("NOT (EXISTS (#{ne_subquery.to_sql}))").where(company_id: @company.id)
这似乎可行,但我们在这一行代码中遇到了同样的问题:

first.union(second)
每当我们运行这部分查询时,绑定就会丢失。第一个和第二个都是活动记录对象,但一旦我们“联合”它们,它们就会丢失绑定并成为arel对象

我们尝试循环查询并手动替换绑定,但似乎无法使其正常工作。我们应该怎么做呢

编辑:

我们还尝试从第一个和第二个对象中提取绑定值,然后在arel对象中手动替换它们,如下所示:

union.grep(Arel::Nodes::BindParam).each_with_index do |bp, i|
  bv = bind_values[i]
  bp.replace(Customer.connection.substitute_at(bv, i))
end
但是,它失败了,因为:

NoMethodError: undefined method `replace' for #<Arel::Nodes::BindParam:0x007f8aba6cc248>
NoMethodError:未定义的方法“替换”#

这是rails github repo中建议的解决方案。

我知道这个问题有点老了,但错误听起来很熟悉。我在存储库中有一些注释和我们的解决方案,所以我想与大家分享一下

我们收到的错误是:

PG::ProtocolViolation:错误:绑定消息提供0个参数,但 准备好的语句“”需要1

如你所见,我们的情况有点不同。我们没有8个绑定值。然而,我们的单一绑定值仍然被破坏。我改变了事物的名称以保持其通用性

first_level = Blog.all_comments
second_level = Comment.where(comment_id: first_level.select(:id))
third_level = Comment.where(comment_id: second_level.select(:id))
Blog。所有的注释都是我们拥有单一绑定值的地方。这就是我们正在失去的部分

union = first_level.union second_level
union2 = Comment.from(
  Comment.arel_table.create_table_alias union, :comments
).union third_level

relation = Comment.from(Comment.arel_table.create_table_alias union2, :comments)
我们创建了一个与您非常相似的联合,只是需要联合三个不同的查询

为了得到此时丢失的绑定值,我们做了一个简单的赋值。最后,这个案子比你的要简单一点。不过,这可能会有所帮助

relation.bind_values = first_level.bind_values
relation

顺便说一下,这是我们在做这件事时发现的。自从这个问题发布后,它似乎没有任何更新。

我认为一些查询可以写得更好(例如:second=Customer.joins(:import\u logs)。其中(import\u logs:{/*ImportLog conditions here*/}))。。。我不明白你想做什么,我也有同样的问题。请参阅对此帖子的公认答案:将
a.union(b)
替换为
Arel::Nodes::UnionAll.new(a,b)
为我解决了绑定问题。