Rails で次の生のクエリを実行しようとしていますが、失敗します。
query = 'SELECT * FROM users WHERE id IN ($1);'
results = ActiveRecord::Base.connection.exec_query(query, "My query", [ [1,2] ]);
何が間違っているのでしょうか?
私が受け取ったエラーは次のように始まります:
Could not log "sql.active_record" event. NoMethodError: undefined method `binary?' for 1:Fixnum
明らかに、私は[1, 2]
何らかの方法でバインドパラメータを誤用していますが、適切な例を自分で見つけることができませんでした。
PS これは、ActiveRecord の呼び出しチェーンに変換できない、はるかに高度なクエリから派生した、最小限の失敗例です。言い換えると、クエリを構築するときに Arel に頼ることはできません。
PPS私は使用しておりrails 4.0.1
、postgresql 9.3
ベストアンサー1
NoMethodErrorはログ記録から来ていると思います。exec_query
、次のようになります:
def exec_query(sql, name = 'SQL', binds = [])
log(sql, name, binds) do
# call exec_no_cache(sql, binds) or exec_cache(sql, binds)...
次に、exec_cache
、次のようになります:
def exec_cache(sql, binds)
#..
@connection.send_query_prepared(stmt_key, binds.map { |col, val|
type_cast(val, col)
})
したがって、 はbinds
列/値のペアであるはずです。PostgreSQL ドライバーは、 がcol
列オブジェクトであることを期待しているため、 にその名前と のフォーマット方法を尋ねることができます。その情報は、の呼び出しval
によって使用され、 Rails ログにきれいで人間が読めるものを生成します。少し実験してみると、を として使用でき、すべてがうまくいくことがわかります。log
exec_query
nil
col
つまり、私たちは次の段階に進みました:
exec_query(
'SELECT * FROM users WHERE id IN ($1)',
'my query',
[ [nil, [1,2]] ]
)
基盤となるドライバーは配列の処理方法を知っている場合と知らない場合があります[1,2]
。テストに使用できるのは PostgreSQL 拡張機能を備えた Rails3 のみで、 は使用されません[1,2]
。Rails4 でも配列が使用できない場合は、引数を 1 つずつ渡すことができます。
exec_query(
'SELECT * FROM users WHERE id IN ($1, $2)',
'my query',
[ [nil,1], [nil,2] ]
)