🍋

【Rails】CarrierWaveの使い方をざっくりまとめてみた

2021/07/20に公開

1.この記事をなぜ書いたか

CarrierWaveの使い方を忘れてしまったので、復習の意味で記事を作成しました。

記事の中で間違いがある場合、コメント頂けると嬉しいです。

2.CarrierWaveとはそもそも何か?

CarrierWaveは、Webアプリケーションにファイルアップロード機能を提供するGemです。CarrierWaveを使うことで、Webアプリケーションにファイルアップロード機能を追加できます。

3.アップローダーとは何か?

アップローダーとはクラスオブジェクトです。このクラスから生成されたオブジェクトを使って、ファイル名やファイルの保存先を取得できます。また、アップローダーにはファイルアップロードに関する設定を書くことができます。
分かりづらくなってきたので、以下にアップローダーの特徴をまとめます。

  • アップローダーはクラスオブジェクトである。
  • アップローダーから生成されたオブジェクトを使って、ファイル名やファイルの保存先を取得できる。
  • アップローダーにはファイルアップロードに関する設定を書ける。

それぞれの特徴を順番に説明して行きます。

  • アップローダーはクラスオブジェクトである。
    アップローダーはCarrierWaveをインストールして、rails generate uploader アップローダー名コマンドを実行すると作成できます。ファイルを見ると、確かにクラスオブジェクトであることが確認できました。
app/uploaders/avatar_uploader.rb
  class AvatarUploader < CarrierWave::Uploader::Base
    def store_dir
      "uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}"
    end

    def default_url
      'sample.jpg'
    end
  
    def extension_allowlist
      %w(jpg jpeg gif png)
    end
  end
  • アップローダーから生成されたオブジェクトを使って、ファイル名やファイルの保存先を取得できる。
    アップローダーを使うには、まずファイル名を保存するカラムにアップローダーを取り付ける必要があります。 こうすることで、レコードの保存時に自動的にファイルをpublic/uploads配下に保存できるようになります。そして、DBのファイル名を保存するカラムにはファイル名のみ保存されます。 どうやってカラムにアップローダーを取り付けるかは実装手順で説明します。また、カラムにアップローダーを取り付けることによって、モデルのインスタンス生成時に、アップローダークラスのオブジェクトを同時に生成します。そのオブジェクトはインスタンス名.ファイル名を保存するカラム名で呼び出すことができます。そのオブジェクトをレシーバとしてurlメソッドやavatar_identifierメソッドを使うと、ファイル名やファイルの保存先を取得できます。文章だと伝わりづらいので、以下の画像を用いて順番に説明します。(以下の画像では、ファイル名を保存するカラム名をavatarとしています。また、ファイルは画像ファイルを使っています。)
  1. 画像ファイルをアップロードする時に処理を止めます。処理を止めることで、アクション内の処理を確認できます。
    Image from Gyazo
  2. 更新するボタンを押した時に送られるparamsを見ると、avatarキーのバリューに画像ファイルの情報があることを確認できます。
    Image from Gyazo
  3. updateアクション内のuser = User.find(current_user.id)のuserが持つavatarカラムを見ると、アップローダークラスのオブジェクトを確認できます。
    Image from Gyazo
  4. updateアクションを実行した後にuserが持つavatarカラムを見ると、アップローダークラスのオブジェクトに画像ファイルの情報が代入されていることが確認できます。
    Image from Gyazo
  5. アップローダークラスのオブジェクトをレシーバとして、urlメソッドやavatar_identifierメソッドを使うと、ファイル名やファイルの保存先を取得できることが確認できました。
    Image from Gyazo
  6. 終了
  • アップローダーにはファイルアップロードに関する設定を書く。
    以下の画像のように、アップローダークラスでメソッドのオーバーライドをすることによって、デフォルトの設定を変更できます。
app/uploaders/avatar_uploader.rb
  class AvatarUploader < CarrierWave::Uploader::Base
    #アップロードしたファイルの保存先を指定する。
    def store_dir
      "uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}"
    end
    
  #画像がアップロードされてない時に、'sample.jpg'を表示する。この画像はassets/images配下に事前に配置しておく。
   def default_url
      'sample.jpg'
    end
    
    #アップロードを許可するファイル種類を指定する。
    def extension_allowlist
      %w(jpg jpeg gif png)
    end
  end

4.CarrierWaveを用いた画像ファイルアップロード機能の実装手順

今回は、既存のWebアプリケーションに画像ファイルアップロード機能を実装します。
以下に手順を示します。

  1. Gemfileに以下のコードを書きます。
Gemfile
  gem 'carrierwave', '~> 2.0'
  1. ターミナルで以下のコマンドを実行します。
ターミナル
  bundle install
  1. ターミナルで以下のコマンドを実行します。その結果、アップローダーが作成されます(Avatarはアップローダーの名前です)。アップローダーはapp/uploaders/avatar_uploader.rbで確認できます。
ターミナル
  rails generate uploader Avatar
  1. Avatarアップローダーに以下のコードを書きます。
app/uploaders/avatar_uploader.rb
  class AvatarUploader < CarrierWave::Uploader::Base
    def store_dir
      "uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}"
    end

    def default_url
      'sample.jpg'
    end
  
    def extension_allowlist
      %w(jpg jpeg gif png)
    end
  end
  1. アップロードした画像ファイルは、public/uploads/モデル名/画像のカラム名/id」配下に保存されます。アップロードした画像ファイルをGithubに上げたくないので、.gitignoreに以下のコードを書きます。
.gitignore
  /public/uploads
  1. アップローダーをモデル内のカラムに取り付けたいです。 そのため、初めに画像ファイル名保存用のカラムをDBに作ります(カラム名はavatarにします。型はStringです)。
シェル
  rails g migration add_avatar_to_users avatar:string
  rails db:migrate
  1. モデルファイルを開き、以下のコードを書いてアップローダーをカラムに取り付けます。こうすることで、レコードの保存時に自動的に画像ファイルをpublic/uploads配下に保存できるようになります。そして、DBのavatarカラムには画像ファイル名のみ保存されます。
app/models/user.rb(一部抜粋)
  class User < ApplicationRecord
    mount_uploader :avatar, AvatarUploader
  end
  1. Userコントローラのストロングパラメータに、avatarカラムを追加します。
users_controller.rb(一部抜粋)
  def profile_params
    params.require(:user).permit(:email, :last_name, :first_name, :avatar)
  end
  1. 画像ファイルを送信したいフォームに、以下のコードを追加します。<%= image_tag user.avatar.url, class: 'rounded-circle mt-3', id: 'preview', size: '100x100' %>はプレビュー画像を表示するコードです。
_profile_form.html.erb(一部抜粋)
  <div class="form-group">
    <%= f.label :avatar %>
    <%= f.file_field :avatar, onchange: 'previewImage()', class: 'form-control' %>
    <%= f.hidden_field :avatar_cache %>
    <%= image_tag user.avatar.url, class: 'rounded-circle mt-3', id: 'preview', size: '100x100' %>
  </div>
  1. JavaScriptでプレビュー機能を作成します。
assets/javascripts/common.js
  function previewImage() {
    const target = this.event.target;
    const file = target.files[0];
    const reader  = new FileReader();
    reader.onloadend = function () {
        const preview = document.querySelector("#preview")
        if(preview) {
            preview.src = reader.result;
        }
    }
    if (file) {
        reader.readAsDataURL(file);
    }
  }
  1. 画像を表示したいビューテンプレートに以下のコードを書きます。
views/profiles/show.html.erb(一部抜粋)
  <%= image_tag @user.avatar.url, class: 'rounded-circle mr15', width: '40', height: '40' %>
  1. 終了

実施にフォームを送信して、アップロードができることを確認できました。
Image from Gyazo

5.アップローダークラスのオブジェクトが使える代表的なメソッド

以下に、アップローダークラスのオブジェクトが使える代表的なメソッドをまとめます。

  • url
  • avatar_identifier

順番に説明します。

  • url
    urlメソッドを使うと、アップローダークラスのオブジェクトが所有している画像ファイルの保存先urlを取得できます。public配下に置く画像ファイルは、Railsの仕様でブラウザに直接送信されるので、urlメソッドとimage_tagを使って画像を表示できます。
    Image from Gyazo
  • avatar_identifier
    avatar_identifierメソッドを使うと、アップローダークラスのオブジェクトが所有している画像ファイル名を取得できます。
    Image from Gyazo

6.MiniMagickについて

MiniMagickを使うと、画像のサイズを変更できます。事前にImageMagickのインストールが必要です。こちらのサイトで詳しく解説されています。
https://techtechmedia.com/carrierwave-minimagick-image/
アップローダークラスに以下のコードを書くと、画像サイズの変更ができます。

app/uploaders/board_image_uploader.rb(一部抜粋)
  include CarrierWave::MiniMagick
  process resize_to_limit: [300, 200]

7.終わり

アップローダーの挙動をちゃんと理解した訳ではないので、いずれコードリーディングしようと思います。
この記事が少しでも役に立てば幸いです!

8.参考文献

https://github.com/carrierwaveuploader/carrierwave
https://github.com/minimagick/minimagick
https://pikawaka.com/rails/carrierwave
https://techtechmedia.com/carrierwave-minimagick-image/

Discussion