¿Cómo construye Rails una statement MySQL?

Tengo el siguiente código que se ejecuta en heroku dentro de un controlador que falla intermitentemente . Es obvio que debería funcionar para mí, pero debo estar perdiendo algo.

@artist = Artist.find(params[:artist_id])

El hash de parámetros se ve así:

 {"utf8"=>"      ", "authenticity_token"=>"XXXXXXXXXXXXXXX", "password"=>"[FILTERED]", "commit"=>"Download", "action"=>"show", "controller"=>"albums", "artist_id"=>"62", "id"=>"157"} 

El error que recibo se ve así:

 ActiveRecord::StatementInvalid: Mysql::Error: : SELECT `artists`.* FROM `artists` WHERE `artists`.`id` = ? LIMIT 1 

Fíjate en los artistas WHERE . id = ? parte de la statement? Se trata de encontrar una identificación de marca de interrogación. Meaning Rails no está pasando en los params[:artist_id] que obviamente está en el hash params. Estoy en completa pérdida.

Recibo el mismo error en diferentes páginas al intentar seleccionar el registro de una manera similar.

Mi entorno: Cedar Stack en Heroku (esto solo ocurre en Heroku), Ruby 1.9.3, Rails 3.2.8, archivos alojados en Amazon S3 (aunque dudo que importe), utilizando la gem mysql (no mysql2 , que no lo hace) t funciona en absoluto), base de datos MySQL ClearDB.

Aquí está el rastro completo .

Cualquier ayuda sería tremendamente apreciada.

intenta sql?

Si es solo esta afirmación y está causando problemas de producción, ¿puede omitir el generador de consultas solo por ahora? En otras palabras, a muy corto plazo, simplemente escriba el SQL usted mismo. Esto te dará un poco de tiempo.

 # All on one line: Artist.find_by_sql "SELECT `artists`.* FROM `artists` WHERE `artists`.`id` = #{params[:artist_id].to_i} LIMIT 1" 

¿Explica ARel / MySQL?

Rails puede ayudar a explicar lo que MySQL está tratando de hacer:

 Artist.find(params[:artist_id]).explain http://weblog.rubyonrails.org/2011/12/6/what-s-new-in-edge-rails-explain/ 

Quizás pueda descubrir algún tipo de diferencia entre las consultas que tienen éxito y las que fallan, como por ejemplo, cómo la explain utiliza los índices u optimizaciones.

joya mysql2?

¿Puedes intentar cambiar de la gem mysql a la gem mysql2? ¿Qué error obtienes cuando cambias a la gem mysql2?

¿volatilidad?

Tal vez haya algo más que cambie el hash de params sobre la marcha, por lo que lo ve cuando lo imprime, pero ¿ha cambiado para cuando se ejecuta la consulta?

Intente asignar la variable tan pronto como reciba los parámetros:

 artist_id = params[:artist_id] ... whatever code here... @artist = Artist.find(artist_id) 

no los params hash?

Usted escribió “Meaning Rails no está pasando en los parámetros [: artist_id] que obviamente está en el hash de parámetros”. No creo que ese sea el problema. Espero que veas esto porque Rails está usando el “?” como un marcador de posición para una statement preparada.

Para averiguarlo, ejecute los comandos sugeridos por @Mori y compárelos; Deberían ser iguales.

 Article.find(42).to_sql Article.find(params[:artist_id]).to_sql 

declaraciones preparadas?

Podría ser un problema de caché de sentencias preparadas, cuando la consulta se ejecuta realmente.

Aquí está el código que está fallando … y hay una gran advertencia.

 begin stmt.execute(*binds.map { |col, val| type_cast(val, col) }) rescue Mysql::Error => e # Older versions of MySQL leave the prepared statement in a bad # place when an error occurs. To support older mysql versions, we # need to close the statement and delete the statement from the # cache. stmt.close @statements.delete sql raise e end 

Intente configurar su base de datos para desactivar las declaraciones preparadas, para ver si eso hace una diferencia.

En su archivo ./config/database.yml :

 production: adapter: mysql prepared_statements: false ... 

errores con declaraciones preparadas?

Puede haber un problema con Rails ignorando esta configuración. Si desea saber mucho más al respecto, consulte esta discusión y corrección de errores por Jeremey Cole y Aaron: https://github.com/rails/rails/pull/7042

Heroku puede ignorar la configuración. Esta es una manera de intentar anular Heroku parcheando la configuración de ready_statements : https://github.com/rails/rails/issues/5297

¿Eliminar el caché de consulta?

Intente eliminar ActiveRecord QueryCache para ver si eso hace una diferencia:

 config.middleware.delete ActiveRecord::QueryCache http://edgeguides.rubyonrails.org/configuring.html#configuring-middle 

prueba postgres?

Si puedes probar Postgres, eso también podría aclararlo. Puede que esa no sea una solución a largo plazo para usted, pero aislaría el problema a MySQL.

La statement de MySQL es obviamente incorrecta, pero el código de Ruby que mencionaste no lo produciría. Algo está mal aquí, ya sea que uses un código Ruby diferente (quizás uno de un before_filter) o que pases un parámetro diferente (como params [: artist_id] = “?”). Parece que usas recursos nesteds, algo así como Artist has_many :albums . Tal vez la variable @artist no se inicializa correctamente en la acción anterior, por lo que params [: artist_id] no tiene el valor correcto?