ruby-on-rails - Arel + Rails 4.2 导致问题(绑定(bind)丢失)

标签 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_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.where 中来解决查询的第一部分(遇到相同的没有绑定(bind)的 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)

每当我们运行这部分查询时,绑定(bind)就会丢失。 first 和 second 都是事件记录对象,但一旦我们“合并”它们,它们就会失去绑定(bind),成为 arel 对象。

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

编辑:

我们还尝试从 first 和 second 中提取绑定(bind)值,然后像这样在 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>

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

最佳答案

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

我们收到的错误是:

PG::ProtocolViolation: ERROR: bind message supplies 0 parameters, but prepared statement "" requires 1

如您所见,我们的情况有点不同。我们没有 8 个绑定(bind)值。然而,我们的单一绑定(bind)值仍然被破坏。我更改了事物的命名以使其通用。

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.all_comments 是我们拥有单一绑定(bind)值的地方。这就是我们正在失去的部分。

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)

我们创建了一个与您非常相似的联合,只是我们需要联合三个不同的查询。

此时为了获取丢失的绑定(bind)值,我们做了一个简单的赋值。最后,这个案例比你的要简单一些。但是,它可能会有所帮助。

relation.bind_values = first_level.bind_values
relation

顺便说一句,这是GitHub issue我们在研究这个的时候发现了。自从发布此问题以来,它似乎没有任何更新。

关于ruby-on-rails - Arel + Rails 4.2 导致问题(绑定(bind)丢失),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33641601/

相关文章:

mysql - 从Rails 3中的ActiveRecord查询MySQL中的一个月或一周的日期

arrays - 按值从高到低对哈希数组进行排序

php - Yii2 使用存储在数组中的值填充更新表单

ruby-on-rails - Activerecord按ENUM分组

ruby-on-rails - 如何使用sub uri通过passenger/nginx登录rails 3.2.12

javascript - 如果出现验证错误,如何在 Rails 中保持模式打开

ruby-on-rails - Spree 可以允许我在我的电子商务应用程序中包含 'Vendors' 吗?

ruby - 在 Ruby 中将唯一的种子字符串转换为随机但确定的浮点值

ruby - 在文件名末尾插入字符(扩展名之前)?

mysql - rails : Garble data as it leaves the database