LoginSignup
2
1

More than 1 year has passed since last update.

RailsでWebP出し分けをimage_tagと同じ使い勝手で実装する

Last updated at Posted at 2021-09-05

TL;DR

  1. ApplicationHelperにimaget_tagと同じ使い勝手のpicture_tagメソッドを作成
  2. 従来フォーマットの画像 + .webp という形式で画像を保存
  3. 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

参考rails / rails - actionview

解決策

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を作っちゃうというのも手だと思います。

2
1
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1