2
4

More than 3 years have passed since last update.

【Rails/CarrierWave/MiniMagick】縦長と横長専用のCSSクラス名をアップロードした画像のimgタグに与える

Last updated at Posted at 2020-12-29

はじめに

ユーザーがアップロードする画像が縦長と横長がバラバラのため、画像一覧が美しく並ばない問題がありました。

スクリーンショット 2020-12-29 18.48.37.jpeg

その問題を解決するために、縦長と横長専用のCSSクラス名を画像に与え、画像を正方形にマスクする機能を追加しました。

その実装手順を記していきます。

前提/実装環境

  • 開発環境はDockerを使用
  • Ruby:2.6.3のDockerイメージを使用
  • Ruby on Rails:6.0.3
  • CarrierWave:2.1.0」「MiniMagick:4.10.1」のgemを使用
  • CarrierWave:2.1.0」は画像をそのままのサイズでアップロードできるところまでは実装済み

仕様

  1. 画像アップロード時に「CarrierWave」gemで3つのサイズに画像をリサイズ
    1. 通常サイズ:1024*1024
    2. ミディアムサイズ:512*512
    3. スモールサイズ:128*128
  2. 「MiniMagick」gemを使用し、画像のサイズを取得、縦長・横長画像専用のクラスを与える
  3. CSSでマスクをかけて正方形に描画するようにする

実装手順

【1】画像アップロード時に「CarrierWave」gemで3つのサイズに画像をリサイズ

まず、画像アップロード時に「CarrierWave」gemで3つのサイズに画像をリサイズできるようにしていきます。
リサイズできるようにするために下記の作業を行います。

  • 「Imagemagick」をインストール
  • 「MiniMagick」gemをインストール
  • リサイズの設定を「CarrierWave」gemの設定ファイルで行う

「CarrierWave」でリサイズを行うためには、「MiniMagick」gemのインストールが必要で、
「MiniMagick」gemを使用できるようにするためには、「Imagemagick」というソフトウェアのインストールが必要なため、
上記の作業を行います。

下記のコードの引用にあるように、「CarrierWave」のuploader設定ファイルにある、
「MiniMagick」gemファイルをincludeするコードのコメントアウトを外することで、
画像のリサイズができるようになります。

app/uploaders/****_uploader.rb
class MyUploader < CarrierWave::Uploader::Base
 include CarrierWave::MiniMagick #<= コメントアウトされた「MiniMagick」gemを外することで、resizeができるようになる

 process resize_to_fit: [800, 800]

 version :thumb do
   process resize_to_fill: [200,200]
 end

end

下記の引用にあるように、「MiniMagick」gemファイルで画像をリサイズするためには、
「Imagemagick」のインストールが必要とのことです。

Note: You must have Imagemagick installed to do image resizing.
https://github.com/carrierwaveuploader/carrierwave

DockerfileでImagemagickをインストール

私は開発環境にDockerを使用しているので、下記のようにrubyイメージのDockerfileにインストールコマンドを追加しました。

docker/rails/Dockerfile

FROM ruby:2.6.3

# 省略

RUN apt-get update && apt-get install -y --no-install-recommends\
  nodejs \
  default-mysql-client \
  vim \
  yarn \
  imagemagick \ #<= 追加
  && apt-get clean \
  && rm -rf /var/lib/apt/lists/*

# 省略

gemで「MiniMagick」をインストール

Gemfile
gem "mini_magick"
$ bunndle install

リサイズの設定をcarrierwaveの設定ファイルで行う

私のアップローダー名はimageですので、image_uploader.rbファイルを下記のように編集します。

app/uploaders/image_uploader.rb
class ImageUploader < CarrierWave::Uploader::Base
  include CarrierWave::MiniMagick #<= コメントアウトを外す

  # 省略

  # Create different versions of your uploaded files:
  version :thumb do
    process resize_to_fit: [1024, 1024]
  end

  version :medium_thumb, from_version: :thumb do
    process resize_to_fit: [512, 512]
  end

  version :small_thumb, from_version: :medium_thumb do
    process resize_to_fit: [128, 128]
  end

  # 省略

end

Railsアプリを再起動すると、画像アップロード時に画像がリサイズされるようになっていました。

リサイズのやり方は様々あったのですが、上記は、画像の縦横そのままの比率でリサイズする「resize_to_fit」という処理を使用しました。
その他のリサイズ方法はGitHuのMiniMagickのリポジトリに説明がありましたので、そちらを参照してください。

【2】 「MiniMagick」gemを使用し、画像のサイズを取得、縦長・横長画像専用のクラスを与える

今回は画像を様々な箇所で画像を正方形で出したかったので、画像の取得を、メソッドの引数でmedium_thumbsmall_thumbなどのように入力することで、画像を取得し分けられるようにし、
HTML出力部分はパーツ化させて汎用性をもたせるようにしました。

よって下記の作業を行いました。

  • 画像の取得を、メソッドの引数でmedium_thumbsmall_thumbなどのように入力することで、画像を取得し分けられるようにする
  • パーツ化させたhtml.erbファイルを作成

画像の取得を、メソッドの引数でmedium_thumbsmall_thumbなどのように入力することで、画像を取得し分けられるようにする

コールバック関数の機能を利用し、引数で画像を取得できるようにコードを作成します。
既にアプリをデプロイして利用しているユーザーが存在するため、リサイズされた画像が存在しないときは、オリジナル画像を出力するようにしています。

app/controllers/application_controller.rb

class ApplicationController < ActionController::Base


  protected

    # Call the method to get the uploaded image
    def get_uploaded_image(image, method = "thumb")
      self.send(method.to_sym, image)
    end
    helper_method :get_uploaded_image

    # Returns the value of the src attribute of
    # the img tag of the thumbnail size image.
    def thumb(image)
      unless image.thumb.blank?
        return image.thumb.url.to_s
      end

      image.url.to_s
    end

    # Returns the value of the src attribute of
    # the img tag for a medium-sized thumbnail image.
    def medium_thumb(image)
      unless image.thumb.blank?
        return image.medium_thumb.url.to_s
      end

      image.url.to_s
    end

    # Returns the value of the src attribute
    # of the img tag for a small-sized thumbnail image.
    def small_thumb(image)
      unless image.thumb.blank?
        return image.small_thumb.url.to_s
      end

      image.url.to_s
    end
end

パーツ化させたhtml.erbファイルを作成

下記のファイルで、縦長か、横長かを「MiniMagick」のメソッドで判定して、クラス名を与えます。
参考:MiniMagickのGitHubリポジトリ

app/views/layouts/_img-square.html.erb
<%
unless image.blank?
  image_url = get_uploaded_image(image, version)
  image_obj = MiniMagick::Image.open("#{Rails.root.to_s}/public#{image_url}")
  class_name = image_obj.width >= image_obj.height ? "img-square__width":"img-square__height"
  img_width = image_obj.width
  img_height = image_obj.height
else
  image_url = "nophoto.jpg"
  class_name = "img-square__width"
  img_width = 600
  img_height = 600
end
%>
<div class="img-square"><%= image_tag image_url, class: class_name, width: img_width, height: img_height %></div>

取得する画像が存在しない場合は、nophoto画像を取得するようにしています。

上記のパーツを使用して画像を呼び出すためには、下記のようにして画像を呼び出します。

html.erb
<%= render partial: 'layouts/img-square', locals: { image: current_user.image, version: "small_thumb" } %>

【3】CSSでマスクをかけて正方形に描画するようにする

最後は、SCSSファイルで画像を縦・横それぞれのクラス名に合わせてマスクするようにSCSSのコードを書いていきます。

app/assets/stylesheets/application.scss

.img-square {
  width: 100%;
  padding-top: 50%;
  padding-bottom: 50%;
  position: relative;

  @at-root {
    #{&}__height {
      width: 100%;
      height: auto;
      position: absolute;
      top: -50%;
      bottom: -50%;
      right: -100%;
      left: -100%;
      margin: auto;
    }

    #{&}__width {
      height: 100%;
      width: auto;
      max-width: none;
      position: absolute;
      top: -100%;
      bottom: -100%;
      right: -100%;
      left: -100%;
      margin: auto;
    }
  }
}

完成物

スクリーンショット 2020-12-29 18.48.44.png

わからなかった箇所・課題

  • 今後、application_controller.rbにメソッドを追加していくと、コードが増えることにより、カオスになっていくことが予想されるため、コードを整理できるようにしていく必要がありそう。。。
  • オリジナル画像は削除できるようにできるとさらにGood?オリジナル画像は容量が大きいこともあるため、サーバー容量が圧迫していくことが予想されるため

さいごに

わからない箇所がありますが、なんとか記事一覧を正方形で並べるところまで実装できたのでよかったです。
画像サイズは、Ruby専用メソッドで取得ができるのかなと思ったのですが、実際調べると無かったので、「MiniMagick」gemがあって良かった。

2
4
0

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
4