2015-11-10 46 views
16

我々は最近のRails 4.1から4.2レールにアップグレードし、私たちは、このタイプのエラーを取得しているので、AREL + ActiveRecordのを使用しての問題を見ている:AREL + Railsの4.2原因の問題(バインディングが失われて)

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 
     ) 
    ) 

は次のようCustomer.where内であることがexists.notを動かすことによって(バインディングを持っていないのと同じレールのバグに実行しています) so:

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) 

我々は、クエリのこの部分を実行するたびに、バインディングが迷子に。 1つ目と2つ目は両方ともアクティブなレコードオブジェクトですが、それらを「結合」するとすぐにバインディングが失われ、arelオブジェクトになります。

クエリをサイクリングして手作業でバインディングを置き換えてみましたが、正しく動作させることができませんでした。代わりに何をすべきですか?

EDIT:

我々はまた、第一及び第二のバインド値を抽出する試み、及び手動のでよう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> 

これはレールgithub repoで提案された解決策でした。

+0

私はいくつかのクエリが書かれていると思います(例:second = Customer.joins(:import_logs).where(import_logs:{/ * ImportLog条件はここにあります/ *}))...あなたは達成しようとしています。 – muZk

答えて

0

私はこの質問が少し古いことを知っていますが、エラーはよく知られて聞こえました。私はいくつかのノートとソリューションをリポジトリに持っていたので、分かち合うと思いました。私たちが受けていた

エラー:

PG::ProtocolViolation: ERROR: bind message supplies 0 parameters, but prepared statement "" requires 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.all_comments我々は、単一のバインド値を持っているところです。それが私たちが失っている部分です。

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) 

3つの異なるクエリを結合する必要があることを除いて、私はあなたとよく似ています。

この時点で紛失したバインド値を取得するには、単純な割り当てを行いました。結局のところ、これはあなたの場合よりも少し簡単です。しかし、それは役に立つかもしれません。ところで

relation.bind_values = first_level.bind_values 
relation 

が、ここではこれに取り組んでいる間、私たちが発見GitHub issueです。この質問は投稿されて以来、更新がないようです。

関連する問題