Railsで以下のエラーがログに書かれていて、原因を調査したのでその備忘録。バージョンは5.2.1です。

こんな感じな条件で発生しました。

  • テンプレートにcache do endでキャッシュを入れている
  • 同一テンプレート内のrenderの引数に変数・メソッドを指定している
  • 指定した変数名とメソッド名で {複数形の名前}/{名前}のテンプレートが存在しない

テンプレートファイルにこういう感じで書いていると発生します。

コードリーディング

ヘルパーメソッドの cacheは以下のように定義されています。cache_fragment_nameメソッドでキャッシュキーを生成しています。

cache_fragment_nameはskip_digestがfalse、あるいは指定されていない場合に fragment_name_with_digestメソッドを呼び出します。

fragment_name_with_digestActionView::Digestor.digestを呼び出してダイジェストを生成し、そのダイジェストをキャッシュキーの一部として使います。

ActionView::Digestor.digestは依存するファイルを抽出して、それをもとにダイジェストを生成しています。treeメソッドで依存するファイルを抽出しています。

treeメソッドのDependencyTracker.find_dependenciesが依存ファイルを取り出しているメソッドになります。取り出したファイルに対してさらにtreeを呼び出して再帰的に依存ファイルを取り出します。

find_templateで対象のファイルが見つからない場合(例えばrender @varsと指定するとvars/varが依存するファイルパスとして抽出されてファイルが見つからないとき)はelseブロックが実行されることになり、 Couldn't find template for digesting: のエラーが発生することになります。

ActionView::DependencyTracker.find_dependenciesERBTracker.call を呼び出します。

ERBTracker.callはdependenciesメソッドで依存しているファイルを抜き出します。renderメソッドが書かれている場合、renderメソッドに引数のテンプレートファイルに依存するので、テンプレートファイルのパスが抽出されます。

解決策

ダイジェスト生成時の問題なので、skip_digest: trueにしてダイジェストを生成しないようにすればエラーは発生しなくなります。ファイル変更時などでキャッシュ切れしなくなるので、キャッシュ時間が長めな場合は注意が必要ですが…。

renderの引数で分岐するのではなくrenderは静的にしておいて、対象のテンプレートで処理を分岐するのも良さそうです。

ただし、エラーログには残るものの、エラーがraiseしたり予期せぬ挙動になったりするわけではないので、そのままにしておいても実害は無いです。