ruby on rails - left - Cómo ejecutar una actualización raw sql con enlace dinámico en rieles
rails find (6)
Deberías usar algo como:
YourModel.update_all(
ActiveRecord::Base.send(:sanitize_sql_for_assignment, {:value => "''wow''"})
)
Eso serviría. El uso del método de envío ActiveRecord :: Base # para invocar el sanitize_sql_for_assignment hace que el Ruby (al menos la versión 1.8.7) omita el hecho de que el sanitize_sql_for_assignment es en realidad un método protegido.
Quiero ejecutar una actualización raw sql como a continuación:
update table set f1=? where f2=? and f3=?
SQL ejecutará este SQL mediante ActiveRecord::Base.connection.execute
, pero no sé cómo pasar los valores del parámetro dinámico al método.
¿Podría alguien ayudarme con eso?
En Rails 3.1, debe usar la interfaz de consulta:
- nuevo (atributos)
- crear (atributos)
- crear! (atributos)
- find (id_or_array)
- destroy (id_or_array)
- destruye todo
- eliminar (id_or_array)
- eliminar todos
- actualización (ids, actualizaciones)
- update_all (actualizaciones)
- existe?
update y update_all son la operación que necesitas.
Ver detalles aquí: http://m.onkey.org/active-record-query-interface
En algún momento sería mejor utilizar el nombre de la clase principal en lugar del nombre de la tabla:
# Refers to the current class
self.class.unscoped.where(self.class.primary_key => id).update_all(created _at: timestamp)
Por ejemplo, clase base "Persona", subclases (y tablas de bases de datos) "Cliente" y "Vendedor" En lugar de usar:
Client.where(self.class.primary_key => id).update_all(created _at: timestamp)
Seller.where(self.class.primary_key => id).update_all(created _at: timestamp)
Puede usar el objeto de la clase base de esta manera:
person.class.unscoped.where(self.class.primary_key => id).update_all(created _at: timestamp)
Necesitaba usar sql sin procesar porque no logré que Composite_primary_keys funcione con activerecord 2.3.8. Entonces, para acceder a la tabla sqlserver 2000 con una clave primaria compuesta, se requería sql en bruto.
sql = "update [db].[dbo].[#{Contacts.table_name}] " +
"set [COLUMN] = 0 " +
"where [CLIENT_ID] = ''#{contact.CLIENT_ID}'' and CONTACT_ID = ''#{contact.CONTACT_ID}''"
st = ActiveRecord::Base.connection.raw_connection.prepare(sql)
st.execute
Si hay una mejor solución disponible, por favor comparta.
No parece que la API de Rails exponga los métodos para hacer esto genéricamente. Podría intentar acceder a la conexión subyacente y usar sus métodos, por ejemplo, para MySQL:
st = ActiveRecord::Base.connection.raw_connection.prepare("update table set f1=? where f2=? and f3=?")
st.execute(f1, f2, f3)
st.close
No estoy seguro si hay otras ramificaciones para hacer esto (conexiones dejadas abiertas, etc.). Me gustaría rastrear el código de Rails para una actualización normal para ver lo que está haciendo aparte de la consulta real.
El uso de consultas preparadas puede ahorrarle una pequeña cantidad de tiempo en la base de datos, pero a menos que esté haciendo esto un millón de veces seguidas, probablemente sería mejor que simplemente cree la actualización con la sustitución normal de Ruby, por ej.
ActiveRecord::Base.connection.execute("update table set f1=#{ActiveRecord::Base.sanitize(f1)}")
o usando ActiveRecord como dijeron los comentaristas.
ActiveRecord::Base.connection
tiene un método de quote
que toma un valor de cadena (y opcionalmente el objeto de columna). Entonces puedes decir esto:
ActiveRecord::Base.connection.execute(<<-EOQ)
UPDATE foo
SET bar = #{ActiveRecord::Base.connection.quote(baz)}
EOQ
Tenga en cuenta que si está en una migración de Rails o un objeto ActiveRecord puede acortarlo a:
connection.execute(<<-EOQ)
UPDATE foo
SET bar = #{connection.quote(baz)}
EOQ
ACTUALIZACIÓN: Como señala @kolen, debe usar exec_update
en exec_update
lugar. Esto manejará las citas por usted y también evitará la pérdida de memoria. La firma funciona de manera un poco diferente:
connection.exec_update(<<-EOQ, "SQL", [[nil, baz]])
UPDATE foo
SET bar = $1
EOQ
Aquí el último parámetro es una matriz de tuplas que representan parámetros de enlace. En cada tupla, la primera entrada es el tipo de columna y el segundo es el valor. Puede dar nil
para el tipo de columna y Rails generalmente hará lo correcto.
También hay exec_query
, exec_insert
y exec_delete
, dependiendo de lo que necesite.