Rails: アソシエーションを使用する場合、after_touchコールバックのActiveRecord :: StatementInvalid。

作成日 2017年01月05日  ·  3コメント  ·  ソース: rails/rails

ホラ👋

このバグを追跡して再現する方法を見つけるのに少し時間がかかりましたが、ついに私はそれを手に入れました! 私は自分の発見をできる限り説明しようと思います。

5.0.0.1から5.0.1に切り替えた後、テストでActiveRecord::StatementInvalid例外が発生し、 mininumを実行すると、 ActiveRecordが期待どおりにクエリを作成していないようです。 –および拡張子ごとにmaximumaverageなど–計算。 git bisectを使用するまで、どちらが問題であるかを理解できず、リグレッションを導入したコミットがhttps://github.com/rails/rails/pull/25976であることを検出しました。

次に、問題を再現して修正しようとしましたが、PRを開いて修正するのに時間がかかりましたが、問題がさらに奇妙になるため、なぜActiveRecord::StatementInvalidが発生するのか説明できません。 http://api.rubyonrails.org/classes/ActiveRecord/AutosaveAssociation.html 、具体的にPlacing your callbacks after associations is usually a good practice.を読んだときに、自分の側で問題を修正できました。

私が見つけたものをあなたに話し、専門家にそれを解決させようとします。 最初にテストケースの例を確認してください。https://gist.github.com/yukideluxe/36b4092748310bc8ec020f5e4dad8ea9

  1. これは、コールバックがhas_manyの関連付けの前に指定されている場合、および関連付けられたレコードを自動保存しようとした場合にのみ発生します。
  2. テストケースでは、 after_touchコールバックを実行するとエラーが発生しますが、 after_createも実行されている場合に限ります。 after_createではSQLクエリはSELECT MIN(`comments`.`id`) FROM `comments` WHERE `comments`.`post_id` IS NULLですが、 before_createについては理解できますが、 after_createにはすでにpost_idがあります😮
  3. bound_attributescommentsアソシエーションのActiveRecord::Associations::CollectionProxyとそのスコープActiveRecord::AssociationRelationは空ですが、アソシエーションの場合はforeign_keyが必要であることがわかりました。関係の
  4. sqliteを使用しても発生しません!!! すべてのクエリは期待どおりに見えます。

これを修正する方法についての私の最初のアイデアは、これを元に戻すことでしたhttps://github.com/rails/rails/blob/master/activerecord/lib/active_record/associations/collection_proxy.rb#L753-L755そもそもその行を紹介するというアイデアでしたが、これがより深刻な問題であるか、まったく問題ではない場合に備えて、あなたも見てください✌️

私の意見では、コールバックが自動保存コールバックの前に実行され、取得した結果が期待どおりでない場合でも、SQLクエリは有効である必要がありますか? どう思いますか?

それを再現する手順

このテストケースを実行しますhttps://gist.github.com/yukideluxe/36b4092748310bc8ec020f5e4dad8ea9

sqliteの使用

ruby test_case.rb

例外なし

mysql2の使用

ARCONN=mysql2 ruby test_case.rb

例外を発生させます

ActiveRecord::StatementInvalid: Mysql2::Error: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '' at line 1: SELECT MIN(`comments`.`id`) FROM `comments` WHERE `comments`.`post_id` =

postgresqlを使用する

ARCONN=postgresql ruby test_case.rb

例外を発生させます

ActiveRecord::StatementInvalid: PG::ProtocolViolation: ERROR:  bind message supplies 0 parameters, but prepared statement "" requires 1
: SELECT MIN("comments"."id") FROM "comments" WHERE "comments"."post_id" = $1

この問題はマスターブランチでも発生しています。https ://github.com/rails/rails/compare/master ... yukideluxe:callbacks-calculation-bugで確認できます。

長い投稿でごめんなさい、私は何も見逃したくありませんでした! 私は自分自身を説明したいと思います。 ご不明な点がございましたら、お気軽にお問い合わせください。 ❤️

With reproduction steps activerecord attached PR

最も参考になるコメント

#25877が統合されてからのクロージング。

全てのコメント3件

#25877で問題が修正されることを確認しました。

素晴らしい@kamipo! コールバックを「推奨」の位置に配置することでこれを回避できるため、急いでいませんが、PRをマージしておくと便利です。 ありがとう!

#25877が統合されてからのクロージング。

このページは役に立ちましたか?
0 / 5 - 0 評価