Eu quero executar uma atualização de sql bruto como abaixo:
update table set f1=? where f2=? and f3=?
Este SQL será executado por ActiveRecord::Base.connection.execute
, mas não sei como passar os valores dos parâmetros dinâmicos para o método.
Alguém poderia me ajudar nisso?
ruby-on-rails
activerecord
rawsql
Ywenbo
fonte
fonte
Respostas:
Não parece que a API Rails expõe métodos para fazer isso genericamente. Você pode tentar acessar a conexão subjacente e usar seus métodos, por exemplo, para MySQL:
Não tenho certeza se existem outras ramificações para fazer isso (conexões deixadas em aberto, etc). Eu rastrearia o código do Rails para uma atualização normal para ver o que ele está fazendo além da consulta real.
Usar consultas preparadas pode economizar um pouco de tempo no banco de dados, mas a menos que você esteja fazendo isso um milhão de vezes seguidas, provavelmente seria melhor apenas construir a atualização com a substituição normal do Ruby, por exemplo
ou usando ActiveRecord como os comentaristas disseram.
fonte
field=#{value}
pois isso o deixa aberto a ataques de injeção de SQL. Se você seguir esse caminho, verifique o módulo ActiveRecord :: ConnectionAdapters :: Quoting .prepare
declaração em Mysql2execute
é um método perigoso e pode causar vazamentos de memória ou outros recursos.ActiveRecord::Base.connection
tem umquote
método que recebe um valor de string (e, opcionalmente, o objeto de coluna). Então você pode dizer o seguinte:Observe se você estiver em uma migração Rails ou um objeto ActiveRecord, você pode encurtar para:
ATUALIZAÇÃO: como @kolen aponta, você deve usar em seu
exec_update
lugar. Isso cuidará da cotação para você e também evitará o vazamento de memória. A assinatura funciona de maneira um pouco diferente:Aqui, o último parâmetro é uma matriz de tuplas que representam os parâmetros de vinculação. Em cada tupla, a primeira entrada é o tipo de coluna e a segunda é o valor. Você pode dar
nil
para o tipo de coluna e o Rails geralmente fará a coisa certa.Existem também
exec_query
,exec_insert
eexec_delete
, dependendo do que você precisa.fonte
execute
é um método perigoso e pode causar vazamentos de memória ou outros recursos.on duplicate key update
todos os lugaresON CONFLICT DO UPDATE
se quiser. Para SQL não bruto, esta gema parece útil: github.com/jesjos/active_record_upsertVocê deve apenas usar algo como:
Isso resolveria o problema. Usar o método ActiveRecord :: Base # send para invocar sanitize_sql_for_assignment faz com que o Ruby (pelo menos a versão 1.8.7) ignore o fato de que sanitize_sql_for_assignment é na verdade um método protegido.
fonte
Às vezes seria melhor usar o nome da classe pai em vez do nome da tabela:
Por exemplo, classe base "Pessoa", subclasses (e tabelas de banco de dados) "Cliente" e "Vendedor" Em vez de usar:
Você pode usar o objeto da classe base desta forma:
fonte
Por que usar SQL bruto para isso?
Se você tiver um modelo para ele, use
where
:Se você não tiver um modelo para ele (apenas a tabela), você pode criar um arquivo e um modelo que herdará de
ActiveRecord::Base
e novamente use
where
o mesmo que acima:fonte
Aqui está um truque que descobri recentemente para executar sql bruto com binds:
onde
ApplicationRecord
define isso:e isso é semelhante a como o AR vincula suas próprias consultas.
fonte
Eu precisei usar sql puro porque falhei em fazer com que o composite_primary_keys funcionasse com o activerecord 2.3.8. Portanto, para acessar a tabela sqlserver 2000 com uma chave primária composta, o sql bruto foi necessário.
Se uma solução melhor estiver disponível, compartilhe.
fonte
No Rails 3.1, você deve usar a interface de consulta:
update e update_all são as operações de que você precisa.
Veja os detalhes aqui: http://m.onkey.org/active-record-query-interface
fonte