【Rails】複数画像を保存したい時のcarrierwaveとMiniMagickの導入


はじめに

syomaと申します。よろしくお願いいたします。
某プログラミングスクールの最終課題で某フリマアプリのクローンにて、商品出品における画像の複数投稿のための下準備でcarrierwaveとMiniMagickを導入しました。

環境

Rails 5.2.4.1
ruby 2.5.1

やりたいこと

  1. carrierwaveの導入
  2. MiniMagickの導入

↓最終形のイメージ

0.下準備

複数画像を投稿する場合は?対多(画像)になるので、Photoテーブルを作成し、カラム名はimageにしようと思います。※1枚のみであれば保存したいテーブルにimageカラムを追記するだけでOK!

保存先のテーブルを用意しましょう

以下のコマンドを実行してPhotoモデルを作成してください。

ターミナル
$ rails g model Photo

作成できたら、下記のファイルを記述を変更します。

db/migrate/****_create_photos.rb
class CreatePhotos < ActiveRecord::Migration[5.2]
  def change
    create_table :photos do |t|
      # ==========ここから追加する==========
      t.string :image, null: false
      t.references :good, foreign_key: true, null: false
      # ==========ここまで追加する==========
      # t.references :good, foreign_key: true, null: falseのgoodは
      # 紐付けたいテーブル名です。私の場合は商品に紐付けたかったのでGoodテーブルに紐づけております。
      # 人によってはテーブル名が異なるかと存じます。
      t.timestamps
    end
  end
end

では、マイグレーションファイルを実行してphotosテーブルを作成します。

ターミナル
$ rails db:migrate

アソシエーションの設定

モデルを作成したらアソシエーションの設定を行います。
アソシエーションとは、2つのモデル同士のつながりを指します。モデルとモデルの間には関連付けを行う必要があります。GoodモデルとPhotoモデルのアソシエーションを設定します。上記2つのモデルの関係性は以下のようになります。

  1. 一つの商品は複数の写真を持つことができる
  2. 写真Aに関して、写真Aに紐づく商品は一つしかない

つまり、GoodモデルとPhotoモデルは「1対多」の関係になります。
では、app/models/good.rbに以下のコードを追加してください。

good.rb
has_many :photos, dependent: :destroy

次にapp/models/photo.rbに以下のコードを追加してください。

photo.rb
belongs_to :good

これで、アソシエーションの設定は完了です。

1. carrierwaveの導入

carrierwaveはファイルを簡単かつ柔軟にアップロードする方法を提供するgem。

carrierwaveのGemをインストール

gemfile
gem "carrierwave"
ターミナル
$ bundle install

CarrierWaveのアップローダーを作成

ターミナル
$ rails g uploader Image

上記のコマンドを実行すると以下のファイルが作成されます。

ターミナル
create  app/uploaders/image_uploader.rb

image_uploader.rbでは、ファイルの保存方法(デフォルトはファイル)、保存パス、ファイルのサイズ、拡張子やファイル名の変換などが変更できます。

モデルのカラムにアップローダーを紐付け

Photoモデルのimageカラムと、先ほど作成したアップローダーImageUploaderと紐付けをします。(ImageUploaderはapp/uploaders/image_uploader.rbのクラスの名前です。)

app/models/photo.rbに以下のコードを追加してください。

photo.rb
class Photo < ApplicationRecord
  belongs_to :good , optional: true
  # ==========ここから追加する==========
  mount_uploader :image, ImageUploader
  # ==========ここまで追加する==========
end

2.MiniMagickの導入

MiniMagickは画像をリサイズできるgemです。Gemfileの最下部に以下のコードを追加します。

gemfile
gem "mini_magick"
ターミナル
$ bundle install

アップローダーの記述を修正

app/uploaders/image_uploader.rbを修正します。

ここで修正するのは以下の3点です。

  1. 4行目のすでに生成されているコードのコメントを外す
  2. 「version :middle」というサイズを指定するコードを追加 ※サイズを指定しない場合は不要
  3. extension_whitelistメソッドのコメントアウトを外す
image_uploader.rb
class ImageUploader < CarrierWave::Uploader::Base
  # Include RMagick or MiniMagick support:
  # include CarrierWave::RMagick
  include CarrierWave::MiniMagick # ここのコメントアウトを外す

  # Choose what kind of storage to use for this uploader:
  storage :file
  # storage :fog

  # Override the directory where uploaded files will be stored.
  # This is a sensible default for uploaders that are meant to be mounted:
  def store_dir
    "uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}"
  end

  # Provide a default URL as a default if there hasn't been a file uploaded:
  # def default_url(*args)
  #   # For Rails 3.1+ asset pipeline compatibility:
  #   # ActionController::Base.helpers.asset_path("fallback/" + [version_name, "default.png"].compact.join('_'))
  #
  #   "/images/fallback/" + [version_name, "default.png"].compact.join('_')
  # end

  # Process files as they are uploaded:
  # process scale: [200, 300]
  #
  # def scale(width, height)
  #   # do something
  # end

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

  # ==========ここから追加する==========
  version :middle do
    process resize_to_fill: [188, 188]
  end
  # ==========ここまで追加する==========

  # Add a white list of extensions which are allowed to be uploaded.
  # For images you might use something like this:

  # ここのコメントアウトを外す
  def extension_whitelist
    %w(jpg jpeg gif png)
  end

  # Override the filename of the uploaded files:
  # Avoid using model.id or version_name here, see uploader/store.rb for details.
  # def filename
  #   "something.jpg" if original_filename
  # end
end
image_uploader.rb
  version :middle do
    process resize_to_fill: [188, 188]
  end

middleというバージョンが作成され、画像を188 x 188ピクセルにリサイズします。

最後に

実際の投稿は
【Ajax+Rails+Carrierwave】個別削除可能な画像複数(10枚まで)投稿
https://qiita.com/syoma/items/09a0d7bbadad35771a4d
にてご案内しております。もし、参考になったと思ったら「いいね」よろしくお願いいたします!

twitterもやっておりますので是非フォローよろしくお願いいたします。
https://twitter.com/syomabusiness
youtubeも始める予定です。