TL;DR
- ApplicationHelperにimaget_tagと同じ使い勝手のpicture_tagメソッドを作成
-
従来フォーマットの画像 + .webp
という形式で画像を保存 - Viewからpicture_tagを呼び出す
前提
一般的にRailsでpicture要素によるWebPの出し分けを行おうとすると以下のように、
view内において4行のコードに2つの画像パスを書くことになります。
sample.html.erb
<picture>
<source srcset="<%= image_path("WebP画像のパス") %>" type="image/webp">
<%= image_tag('従来フォーマット画像のパス') %>
</picture>
参考:railsでpictureタグによるwebp出し分けをする
WebP化したい箇所が少ないのであればこの方法は直感的かつシンプルです。
しかし、対応したい箇所が増えると途端に見通しが悪くなりますし、何よりDRYではありません。
調査
image_tagの実装を確認してみましょう。
asset_tag_helper.rb
# 引数は画像のソースとclass, styleなどを取る(なければ空ハッシュ)
def image_tag(source, options = {})
options = options.symbolize_keys
check_for_image_tag_errors(options)
# Rails 5.1で追加されたconfig項目
# 詳細は以下を確認
# https://y-yagi.tumblr.com/post/160114728555/rails-51%E3%81%A7%E8%BF%BD%E5%8A%A0%E3%81%95%E3%82%8C%E3%81%9Fconfig%E3%81%BE%E3%81%A8%E3%82%81
skip_pipeline = options.delete(:skip_pipeline)
# ここが肝心で、ソース名からasset_pipeline通過後の画像パスを取得している
options[:src] = resolve_image_source(source, skip_pipeline)
if options[:srcset] && !options[:srcset].is_a?(String)
options[:srcset] = options[:srcset].map do |src_path, size|
src_path = path_to_image(src_path, skip_pipeline: skip_pipeline)
"#{src_path} #{size}"
end.join(", ")
end
options[:width], options[:height] = extract_dimensions(options.delete(:size)) if options[:size]
tag("img", options)
end
解決策
image_tagを元にpicture_tagを実装してみましょう
application_helper.rb
def picture_tag(image_source, options = {})
# image_tag同様にskip_pipelineを確認する
skip_pipeline = options.delete(:skip_pipeline)
# WebPのパスを探す
src_path = path_to_image("#{image_source}.webp", skip_pipeline: skip_pipeline)
tag.picture {
tag.source(srcset: src_path, type: 'image/webp') << image_tag(image_source, options)
}
end
# 画像の保存先
app
┗ assets
┗ images
┣ test.png
┗ test.png.webp
sample.html.erb
<!-- viewからの呼び出しはimage_tagと同じ -->
<%= picture_tag "test.png", loading: "lazy" %>
sample.html
<picture>
<!-- webpもちゃんとパスの解決できてます -->
<source srcset="/assets/test.png-8fca8f7a0351d6cc6203f79b4d18da0d1f32d823db5294726104ee587d9eb47f.webp" type="image/webp">
<img loading="lazy" src="/assets/test-49833f6482d22ae5aa5141294877224cf7907cb1de22e321c451666a380f11fe.png" alt="New business consultant">
</picture>
複数個所に入れるならpicture_tagを作っちゃうというのも手だと思います。