2015-11-10 16 views
16

Chúng tôi vừa mới nâng cấp lên Rails 4.2 từ Rails 4.1 và đang nhìn thấy vấn đề với việc sử dụng Arel + ActiveRecord bởi vì chúng tôi đang nhận được loại lỗi:Arel + Rails 4.2 vấn đề gây (bindings bị mất)

ActiveRecord::StatementInvalid: PG::ProtocolViolation: ERROR: bind message supplies 0 parameters, but prepared statement "" requires 8 

Dưới đây là mã được phá vỡ:

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

Chúng tôi đã tìm ra cách để giải quyết một phần đầu tiên của truy vấn (chạy vào cùng một đường ray lỗi không có ràng buộc) bằng cách di chuyển exists.not được trong vòng Customer.where như như vậy:

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) 

Điều này dường như để làm việc nhưng chúng tôi chạy vào cùng một vấn đề với dòng mã này:

first.union(second) 

bất cứ khi nào chúng tôi chạy phần này của truy vấn, các ràng buộc bị lạc. đầu tiên và thứ hai là cả hai đối tượng ghi lại hoạt động nhưng ngay sau khi chúng tôi "đoàn kết" chúng, họ mất các ràng buộc được trở thành đối tượng arel.

Chúng tôi đã cố gắng đi xe đạp qua truy vấn và thay thế thủ công các liên kết nhưng dường như không làm cho nó hoạt động bình thường. Thay vào đó chúng ta nên làm gì?

EDIT:

Chúng tôi cũng đã cố gắng trích xuất các giá trị ràng buộc từ đầu tiên và thứ hai, và sau đó tự thay thế chúng trong đối tượng AREL như vậy:

union.grep(Arel::Nodes::BindParam).each_with_index do |bp, i| 
    bv = bind_values[i] 
    bp.replace(Customer.connection.substitute_at(bv, i)) 
end 

Tuy nhiên, nó không thành công vì:

NoMethodError: undefined method `replace' for #<Arel::Nodes::BindParam:0x007f8aba6cc248> 

Đây là giải pháp được đề xuất trong repo đường ray github.

+0

Tôi nghĩ rằng một số truy vấn có thể được viết tốt hơn (ví dụ: second = Customer.joins (: import_logs) .where (import_logs: {/ * ImportLog conditions here * /})) ... Tôi không hiểu bạn đang cố gắng hoàn thành. – muZk

Trả lời

0

Tôi biết câu hỏi này hơi cũ, nhưng lỗi có vẻ quen thuộc. Tôi đã có một số ghi chú và giải pháp của chúng tôi trong một kho lưu trữ, vì vậy tôi nghĩ rằng tôi muốn chia sẻ.

Các lỗi chúng tôi đã nhận được là:

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

Như bạn có thể thấy, tình hình của chúng tôi là một chút khác nhau. Chúng tôi không có 8 giá trị liên kết. Tuy nhiên, giá trị ràng buộc duy nhất của chúng tôi vẫn bị che khuất. Tôi đã đổi tên của mọi thứ để giữ cho nó chung chung.

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 là nơi chúng tôi có giá trị liên kết đơn. Đó là mảnh chúng tôi đang mất.

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) 

Chúng tôi tạo một liên minh giống như bạn ngoại trừ việc chúng tôi cần phải kết hợp ba truy vấn khác nhau.

Để nhận giá trị liên kết bị mất tại thời điểm này, chúng tôi đã thực hiện một nhiệm vụ đơn giản. Cuối cùng, điều này đơn giản hơn một chút so với của bạn. Tuy nhiên, nó có thể hữu ích.

relation.bind_values = first_level.bind_values 
relation 

Nhân tiện, đây là số GitHub issue mà chúng tôi đã tìm thấy khi thực hiện việc này. Nó không xuất hiện để có bất kỳ bản cập nhật kể từ khi câu hỏi này đã được đăng mặc dù.

Các vấn đề liên quan