画像アップロード機能[carrierwave Gem]と[mini_magick Gem]

carrierwave Gemとは?
画像をアップロードする為のGemです。

mini_magick Gemとは?
画像加工をしてくれるGemです。


[carrierwave Gemの導入手順]
Gemfileに以下のように記述する。

[Gemfile]

gem "carrierwave"



bundle install

[rails generate uploader アップローダー名前(モデルの画像ファイルを保存するカラム名)] 上記コマンドでアップローダーを作成する。(追加するカラム名は、アップローダーで付けた名前と同じにしなければならない)
アップローダー:ファイルの保存方法、保存先、ファイルのサイズ、拡張子やファイル名の変換などの設定ができる。


アップローダーの各機能の設定

[app/uploaders ファイル]

include CarrierWave::MiniMagick     # mini_magickを利用するという宣言のようなもの(コメントアウトを外す)

def store_dir                  #アップロードファイルが保存される場所の設定(コメントアウトを外す)
    "uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}"
end

def default_url(*args)     #画像がアップロードされていない時に表示する画像の設定(コメントアウトを外す)
    'board_placeholder.png'
end

def extension_allowlist    # アップロードできるファイルの制限設定(コメントアウトを外す)
    %w[jpg jpeg gif png]
end

[default_url]の画像がアップロードされていない時に表示する画像の設定は、画像が保存されるカラムに画像が保存されてなくてnilの時に発動するイメージ。(下記参照)

[app/views ファイル]

<img src="<%= current_user.profile_image.url %>" class="img-circle elevation-2" alt="User Image">

<%= image_tag current_user.profile_image.url, class: "img-circle elevation-2", alt: "User Image" %>

上記はHTML記法とERB記法で最終的に同じHTMLを生成するが、デフォルトの画像が表示されるのはERB記法の時だけ。(画像のカラムがnilの時にデフォルトの画像を表示するがHTML記法だとnilを返さないため。)[profile_image]カラムがnilの時にデフォルトの画像が表示される。



ローカル環境でアップロードした画像ファイルはリモートなどにアップロードしないようgitignoreに以下のように追記する。

[.gitignore]

/public/uploads



画像を保存したいモデルに画像保存のカラムを追加する ex) [rails generate migration add_image_to_board image:string]

rails db:migrate

下記のように記述し、先ほど作成したアップローダーを関連するモデルと紐付ける。(imageカラムに追加した画像のURLをアップローダが処理するイメージ)

[app/models ファイル]

mount_uploader :image, ImageUploader        # mount_uploader :カラム名, アップローダー名



下記のようにform_withのフォーム入力欄に画像を挿入するフォームを追加する。

[app/views ファイル]

<div class="form-group">
      <%= f.label :image  %>
      <%= f.file_field :image, class: "form-control mb-3", accept: 'image/*' %>          # [accept: 'image/*']は、input要素のaccept属性は、サーバーが受け入れるファイルの種類を指定する属性。
      <%= f.hidden_field :image_cache %>      # hidden属性でimage_cacheは、画像を指定したけれども、バリデーションエラーなどにより保存が失敗した場合の画面再表示時などに、画像情報をキャッシュしておくための領域(f.labelなどで記述しているカラム名を使って、カラム名_cacheの形にする。)
</div>

※上記の<%= f.hidden_field :image_cache %>を追加しないと1度画像を挿入して掲示板などを作成しようとした時に、バリデーションエラーとなった部分があり、バリデーションエラー部分を解消して、再度掲示板などを作成した時に最初に挿入した画像が消えてしまう。

保存するカラムを追加したので、以下のようにストロングパラメータにもカラムを追加する。(image_cacheなどの画像情報をキャッシュしておく領域も追加するのを忘れないように。)

[app/controllers ファイル]

private

  def board_params
    params.require(:board).permit(:title, :body, :image, :image_cache)
  end



一覧画面などで保存した画像を表示する
ex)

[app/views ファイル]

<%= image_tag board.image.url %>

※注意
DBの画像保存カラムに保存されるのは、ファイルそのものではなく、ファイルへの参照データになるので、[board.image]ではなく[board.image.url]のようにパスを指定する書き方をする。


エラーメッセージの翻訳ファイルを追加する

[config/locales ファイル]

ja:
  errors:
    messages:
      carrierwave_processing_error: '処理できませんでした'
      carrierwave_download_error: 'はダウンロードできません'
      extension_whitelist_error: "は %{allowed_types}の形式でアップロードしてください"
      extension_blacklist_error: "%{extension}ファイルのアップロードは許可されていません。アップロードできないファイルタイプ: %{prohibited_types}"
      content_type_whitelist_error: "%{content_type}ファイルのアップロードは許可されていません。アップロードできるファイルタイプ: %{allowed_types}"
      content_type_blacklist_error: "%{content_type}ファイルのアップロードは許可されていません"
      rmagick_processing_error: "rmagickがファイルを処理できませんでした。画像を確認してください。エラーメッセージ: %{e}"
      mini_magick_processing_error: "MiniMagickがファイルを処理できませんでした。画像を確認してください。エラーメッセージ: %{e}"
      min_size_error: "を%{min_size}以上のサイズにしてください"
      max_size_error: "を%{max_size}以下のサイズにしてください"


[mini_magick Gemの導入手順]
[mini_magick]Gemを利用するには[Imagemagick]をインストールする必要がある。
[brew install imagemagick]


Gemfileに以下のように記述する。

[Gemfile]

gem "mini_magick"



挿入画像をリサイズする場合は、下記のように設定する

[app/uploaders ファイル]

version :thumb do           # コメントアウトを外して、サイズを任意に設定する
    process resize_to_fit: [300, 200]
end



[app/uploaders]ファイルで設定したリサイズを表示する画像に適用する場合は、以下のように使用する。

[app/views ファイル]

<%= image_tag board.image.thumb.url %>       # 左記のようにthumbメソッドを使う


[resizeの各種使い方]
・resize_to_fill

[app/uploaders ファイル]

version :thumb do
    process resize_to_fill: [400, 300]
end

上記の場合、元画像からwith:400px,height:300pxで切り抜きをする。

・resize_to_fit

[app/uploaders ファイル]

version :thumb do
    process resize_to_fit: [400, 300]
end

上記の場合、元画像の縦横比を維持したままwith:400px,height:300pxでリサイズする。

・resize_to_limit

[app/uploaders ファイル]

version :thumb do
    process resize_to_limit: [400, 300]
end

上記の場合、元画像の縦横比を維持したままwith:400px,height:300pxでリサイズ(resize_to_fitと同じ)して、元画像のサイズが引数に指定されたサイズ以内の場合は、リサイズされない。


<補足>
[.gitignore]に記述せずにコミットやpushしてしまった場合の対象方法 ・すでにファイルをコミットしてからgitignoreを追記してもファイルが管理対象に含まれているため、コミット後は[git rm --cached ファイル名]コマンドでgitの管理対象外に設定すること ・不要なファイルをpushしてしまった場合は、[git rm ファイル名]コマンドでリモートリポジトリから削除する。


参考記事:

carrierwaveの使い方 - Qiita

CarrierWaveを使って、ユーザー画像を設定する。 - Qiita

【Rails】CarrierwaveとMiniMagickを使って画像を投稿する方法|TechTechMedia

CarrierWave+MiniMagickで使う、画像リサイズのメソッド - Qiita

CarrierWave+MiniMagickで使う、画像リサイズのメソッド - Qiita

Rails gem MiniMagick を利用して画像ファイルをリサイズする - Qiita

CarrierWave デフォルトの画像を表示する default_url - 196Log

carrierwaveでundefined method `resize_to_fill'を怒られた時の対応 - Qiita