Недавно мы обновили Rails 4.2 от Rails 4.1 и видим проблемы с использованием 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
)
)
Мы выяснили, как решить первую часть запроса (запускаясь в ту же ошибку рельсов, не имеющих привязок), перемещая существующий. Не для того, чтобы быть внутри Customer.where:
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)
всякий раз, когда мы запускаем эту часть запроса, привязки теряются. первый и второй являются активными объектами записи, но как только мы "объединяем" их, они теряют привязки, становятся объектами isl.
Мы пробовали циклически выполнять запрос и вручную заменяли привязки, но не могли заставить его работать исправно. Что мы должны делать вместо этого?
EDIT:
Мы также попытались извлечь значения привязки с первого и второго и затем вручную заменить их в объекте isl следующим образом:
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.