Подготовленное выражение о Postgresql в Rails

Сейчас я нахожусь в середине перехода от SQLite к Postgresql, и я столкнулся с этой проблемой. Следующий подготовленный оператор работает с SQLite:

id = 5
st = ActiveRecord::Base.connection.raw_connection.prepare("DELETE FROM my_table WHERE id = ?")
st.execute(id)
st.close

К сожалению, он не работает с Postgresql - он выдает исключение в строке 2. Я искал решения и наткнулся на это:

id = 5
require 'pg'
conn = PG::Connection.open(:dbname => 'my_db_development')
conn.prepare('statement1', 'DELETE FROM my_table WHERE id = $1')
conn.exec_prepared('statement1', [ id ])

Это не работает в строке 3. Когда я печатаю исключение, подобное этому

rescue => ex

ex содержит это

{"connection":{}}

Выполняется SQL в командной строке. Любая идея, что я делаю неправильно?

Спасибо заранее!

Ответ 1

Если вы хотите использовать prepare, как это, вам нужно сделать пару изменений:

  • Драйвер PostgreSQL хочет видеть пронумерованные заполнители ($1, $2,...) не вопросительные знаки, и вам нужно дать вашему подготовленному заявлению имя:

     ActiveRecord::Base.connection.raw_connection.prepare('some_name', "DELETE FROM my_table WHERE id = $1")
    
  • Вызывающая последовательность prepare, за которой следует exec_prepared:

    connection = ActiveRecord::Base.connection.raw_connection
    connection.prepare('some_name', "DELETE FROM my_table WHERE id = $1")
    st = connection.exec_prepared('some_name', [ id ])
    

Этот подход работает для меня с ActiveRecord и PostgreSQL, ваша версия PG::Connection.open должна работать, если вы правильно подключаетесь.

Еще один способ - сделать цитату самостоятельно:

conn = ActiveRecord::Base.connection
conn.execute(%Q{
    delete from my_table
    where id = #{conn.quote(id)}
})

Это то, что ActiveRecord обычно делает за вашей спиной.

Непосредственное взаимодействие с базой данных имеет тенденцию быть немного беспорядочным с Rails, поскольку люди Rails не думают, что вы когда-либо должны это делать.

Если вы действительно пытаетесь удалить строку без помех, вы можете использовать delete:

Удалить()

[...]

Строка просто удаляется с помощью оператора SQL delete в первичном ключе записи, и никаких обратных вызовов не выполняются.

Итак, вы можете просто сказать следующее:

MyTable.delete(id)

и вы отправите простой delete from my_tables where id = ... в базу данных.