1

断続的に失敗するコントローラー内のherokuで実行される次のコードがあります。それが私にとってうまくいくはずであることは簡単ですが、私は何かが欠けているに違いありません。

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

パラメータハッシュは次のようになります。

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

私が得るエラーは次のようになります:

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

声明のWHEREアーティスト.IDの部分に気づきましたか?= ?疑問符のIDを見つけようとしています。意味Railsは、params[:artist_id]明らかにparamsハッシュにあるを渡していない。私は完全に途方に暮れています。

同様の方法でレコードを選択しようとすると、異なるページで同じエラーが発生します。

私の環境:Heroku上のCedar Stack(これは、Herokuでのみ発生します)、Ruby 1.9.3、Rails 3.2.8、Amazon S3でホストされているファイル(重要ではないかと思いますが)、mysqlgemを使用しています(mysql2これは機能しません)まったく)、ClearDBMySQLデータベース。

これが完全なトレースです。

どんな助けでも歓迎です。

4

2 に答える 2

6

SQLを試してみますか?

この1つのステートメントだけで、本番環境の問題が発生している場合は、今のところクエリジェネレータを省略できますか?つまり、非常に短期的には、SQLを自分で作成するだけです。これはあなたに少しの時間を買うでしょう。

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

ARel / MySQLは説明しますか?

Railsは、MySQLが何をしようとしているのかを説明するのに役立ちます。

Artist.find(params[:artist_id]).explain

http://weblog.rubyonrails.org/2011/12/6/what-s-new-in-edge-rails-explain/

explainおそらく、インデックスや最適化の使用方法など、成功しているクエリと失敗しているクエリの間にある種の違いを見つけることができます。

mysql2 gem?

mysqlgemからmysql2gemに変更してみてください。mysql2 gemに切り替えると、どのような失敗が発生しますか?

ボラティリティ?

おそらく、その場でparamsハッシュを変更する何かがあるので、それを印刷すると表示されますが、クエリが実行されるまでに変更されますか?

パラメータを受け取ったらすぐに変数を割り当ててみてください。

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

paramsハッシュではありませんか?

あなたは「MeaningRailsは明らかにparamsハッシュにあるparams[:artist_id]を渡していない」と書いています。それが問題だとは思いません。Railsが「?」を使用しているため、これが表示されていると思います。プリペアドステートメントのプレースホルダーとして。

調べるには、@Moriによって提案されたコマンドを実行して比較します。それらは同じである必要があります。

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

プリペアドステートメント?

クエリが実際に実行されるときに、プリペアドステートメントキャッシュの問題である可能性があります。

これが失敗しているコードです-そして大きな太った警告があります。

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

プリペアドステートメントをオフにするようにデータベースを構成して、違いが生じるかどうかを確認してください。

ファイル./config/database.yml内:

production:
   adapter: mysql
   prepared_statements: false
   ...

プリペアドステートメントのバグ?

Railsがこの設定を無視すると問題が発生する可能性があります。それについてもっと知りたい場合は、Jeremey ColeとAaronによるこのディスカッションとバグ修正を参照してください:https ://github.com/rails/rails/pull/7042

Herokuは設定を無視する場合があります。これは、prepared_statementsセットアップにパッチを適用してHerokuをオーバーライドする方法です:https ://github.com/rails/rails/issues/5297

クエリキャッシュを削除しますか?

ActiveRecord QueryCacheを削除して、違いが生じるかどうかを確認してください。

config.middleware.delete ActiveRecord::QueryCache

http://edgeguides.rubyonrails.org/configuring.html#configuring-middle

postgresを試してみませんか?

Postgresを試すことができれば、それも解決する可能性があります。それはあなたにとって長期的な解決策ではないかもしれませんが、それは問題をMySQLに分離するでしょう。

于 2012-09-25T05:55:16.843 に答える
1

MySQLステートメントは明らかに間違っていますが、あなたが言及したRubyコードはそれを生成しません。ここで何か問題があります。別のRubyコード(おそらくbefore_filterからのもの)を使用するか、別のパラメーター(params [:artist_id] = "?"など)を渡します。のようなネストされたリソースを使用しているようArtist has_many :albumsです。@artist変数が前のアクションで正しく初期化されていないため、params [:artist_id]の値が正しくない可能性がありますか?

于 2012-09-25T09:00:11.127 に答える