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

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

# 環境
Rails 5.2.4.1
ruby 2.5.1

# やりたいこと
1. carrierwaveの導入
2. MiniMagickの導入

↓最終形のイメージ
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/586820/997deaa5-ba91-212a-17a0-607b964fffdb.png)

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

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

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

```terminal:ターミナル
$ rails g model Photo
```

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

```ruby: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テーブルを作成します。

```terminal:ターミナル
$ rails db:migrate
```

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

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

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

```ruby:good.rb
has_many :photos, dependent: :destroy
```
次にapp/models/photo.rbに以下のコードを**追加**してください。

```ruby:photo.rb
belongs_to :good
```
これで、アソシエーションの設定は完了です。

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

# carrierwaveのGemをインストール

```Gemfile:gemfile
gem "carrierwave"
```

```terminal:ターミナル
$ bundle install
```


# CarrierWaveのアップローダーを作成
```terminal:ターミナル
$ rails g uploader Image
```
上記のコマンドを実行すると以下のファイルが作成されます。

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

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

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

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

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

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

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

```Gemfile:gemfile
gem "mini_magick"
```

```terminal:ターミナル
$ bundle install
```

# アップローダーの記述を修正
app/uploaders/image_uploader.rbを修正します。

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

1. 4行目のすでに生成されているコードのコメントを外す
2. 「version :middle」というサイズを指定するコードを追加　※サイズを指定しない場合は不要
3. extension_whitelistメソッドのコメントアウトを外す

```ruby: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
```

```ruby: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も始める予定です。