はじめに
実装をしている最中に以下のようなエラーが発生した。
Failure/Error: _query(sql, @query_options.merge(options))
ActiveRecord::StatementInvalid:
Mysql2::Error: This connection is in use by: #<Fiber:0x0000000111111111 (resumed)>
このエラーの解決に少々手間がかかったので、まとめる。
実行バージョン
ruby 3.2.3
Rails 7.1.3
rspec-rails 6.1.3
解決策
ActiveRecordモデルのhas_one_attached
マクロに対して、dependent: :destroy
を追加する
変更前
class Hoge < ApplicationRecord
has_one_attached :csv
end
変更後
class Hoge < ApplicationRecord
has_one_attached :csv, dependent: :destroy
end
エラーの原因について
公式ドキュメントには以下のように書いてあった。
If the :dependent option isn’t set, the attachment will be purged (i.e. destroyed) whenever the record is destroyed.
dependent オプションを特に指定しない場合デフォルトでdependent: :destroy
を指定しなくても良いと書かれていたので、この対応はスルーしていたが、結果的にはここの設定を明示的に行なっていないことが原因だった。
直接的な原因が何なのかはわかっていないが、dependent: :destroy
を明示的に書くことでエラーは解決できた。
想定される直接的な原因としては
- ドキュメントと実際の実装に乖離がある
- テスト環境でのみうまく作用しない
- 親リソース起点でdestroyを実行するとうまくいかない
などが考えられる。
エラー解決に躓いた原因
エラーメッセージから読み取れる情報としては、すでにdbコネクションがFiberによって使われているからdbアクセスうまくできないといった趣旨だった。
つまり、エラーが発生しているテストケース以前に何かしらのエラーの原因となるテストケースが存在しているというふわっとしたことしか把握できなかった。
エラー解決に役立った方法
今回はエラーが起きているテストケースのファイル以前にどのspecファイルが実行されているのかを把握する必要があった。そのため、今回のケースでは以下のやり方で、デバッグするのが効率的だった。
方法は、rspec_helper.rb の末尾に次のコードを埋め込むだけ。
RSpec.configure do |config|
config.before(:all) do
puts "\nRunning: #{self.class.metadata[:file_path]}"
end
end
このコードを埋め込むことで、どのファイル順でrspecが実行されているのかがすぐわかる。
他のやり方としては、rspecが用意しているoptionsを使うという選択肢もある。
rspec -format documentation
を使うことで、どのファイルのテストケースが実行されているかをログから容易に把握できる。