指摘されたこと
RailsとReactで動く画像を表示したかったので、画像をpublic/img/
フォルダに置いてこのように書きました。
return (
<>
<img src="/img/hoge.jpg" alt="hoge" />
</>
)
すると先輩から下記のように指摘を受けました。無断で転載します。
画像のパスはRailsから渡したほうがいいと思います。
public配下ではなく、アセットパイプラインを通したやつを渡してください。
動きはするんだけど、もし画像を差し替えるとなったときに、パスが固定だとしばらくブラウザのキャッシュが働いてすぐに切り替わらないので。アセットパイプラインを通すと、ファイル名にランダムな文字列が付いて、画像が変わるたびに別のパスになります。
なんとなく言いたいことはわかるんだけど、「なんとなく」を潰したいので、きちんと咀嚼しながら修正します。
アセットパイプラインとは?
JS,CSS,画像などのファイルを最小化して連結するためのフレームワーク。
Railsガイドでも、アセットパイプラインが推奨されているとのこと。
以前のRailsでは、すべてのアセットはpublicディレクトリの下のimages、javascripts、stylesheetsなどのサブフォルダに置かれました。アセットパイプライン導入後は、app/assetsディレクトリがアセットの置き場所として推奨されています。
Railsガイドv7.0 - アセットパイプライン「2 アセットパイプラインの利用方法」
なぜアセットパイプラインを通すのか
先輩のコメントそのまんまなんですが、パイプラインを通すとアセットにランダムな文字列を生成して割り当てるみたい。
将来、「画像を置き換えたい、だけど同じファイル名で」となった時に、public配下だと、ファイル名が一緒なので、ブラウザがキャッシュに「あ、そのファイルの画像名なら取りに行かなくてもキャッシュで持ってるぜ」となってサーバーに新しい画像を取りに行ってくれない。アセットパイプラインを通すと、名前が同じであっても違うアセットとみなされてファイル名が別になる。それで置き換えたら即時にその変更が反映されるようになるということですね。これ本記事の最後で検証します。百聞は一見に如かず。
どうやってアセットパイプラインを通したやつを渡すか
画像をapp/assets/images
配下に置きます。
画像のパスを取得するには、Railsのメソッドimage_path
が使えそうでした。
ビューで下記のように書きます。
<%= react_component(
"App",
props: {
hogeImage: image_path("hoge.jpg"),
},
prerender: false
) %>
本課題とは関係ないですが、コントローラなどで画像のパスを取得したい場合は、view_context.image_path
とすると取得できそうです。これでReactの画面で画像を表示できました。
画像のパスはどうなったのか
先輩の指摘「アセットパイプラインを通すと、ファイル名にランダムな文字列が付いて、画像が変わるたびに別のパスになります。」を検証するために、パスがどうなるのか見てみます。HTMLのimgタグのsrcに何が入るのか。
public配下に置いた場合。
/img/hoge.jpg
アセットパイプラインを通した場合。ほほう。画像ファイル名の後にランダムな文字列が入っている!
/assets/hoge-c0d7ed0a339ac8017a3cc703c3bc1353574cc4d5aad524b43046ff35a9cf495c.jpg
ブラウザをリロードしてもう一度表示してみる。当然ながらランダムな文字列は変わっていない。
/assets/hoge-c0d7ed0a339ac8017a3cc703c3bc1353574cc4d5aad524b43046ff35a9cf495c.jpg
同じ名前だが中身は違うファイル名で置き替えてみる。文字列が変わった!
/assets/hoge-2e64510ea882790984b0353c7c7b0ca5c31c78af933d5c09070c7d79aad5204c.jpg
試しに同じファイル名で中身はさっきのファイルに戻してみる。文字列はさっきのに戻るのか、新しいのが生成されるのか。。。さっきのに戻った!ほほう。
/assets/hoge-c0d7ed0a339ac8017a3cc703c3bc1353574cc4d5aad524b43046ff35a9cf495c.jpg