CarrierWave Backgrounderを使って非同期処理を行う

# 環境

- Rails 5.2.2
- CarrierWave 1.3.1
  - 2019/11時点の最新は`2.0.2`ですが、Backgrounderを使うために、1.x台の最新としています。
- CarrierWave Backgrounder 0.4.2

# 注意
## CarrierWave Backgrounderのインストールについて
githubを指定することで、最新の`0.4.2`（且つ、後述のbugを修正したもの）をインストール出来ます。

```ruby:Gemfile
gem 'carrierwave_backgrounder', github: 'leoduquesnel/carrierwave_backgrounder'
```

```ruby:Gemfile.lock
GIT
  remote: git://github.com/leoduquesnel/carrierwave_backgrounder.git
  revision: 128b22a4c8de0db762ca5f005225c87a944c93e1
  specs:
    carrierwave_backgrounder (0.4.2)
      carrierwave (>= 0.5, < 2.0)
      mime-types (~> 2.99)
```

- バージョンを指定せずに、`CarrierWave Backgrounder`をインストールすると、`0.0.2`がインストールされます。この場合、後述の`rails g carrierwave_backgrounder:install`でエラーが出ます。
- [このページ](https://github.com/lardawge/carrierwave_backgrounder/issues/267)を参考にして、リポジトリを指定してインストールしましたが、アップロード時に以下のエラーが出ます。

```
gem "carrierwave_backgrounder", github: 'lardawge/carrierwave_backgrounder'
``` 

```
NoMethodError - undefined method `cache_name' for #<CarrierWave::Mounter:0x00007f9a5dc77488>
```

- 最終的に、[このページ](https://www.bountysource.com/issues/6487243-broken-with-master-branch-of-carrierwave-which-added-support-for-multiple-uploads)を参考にして、前述のリポジトリを使いました。

# 手順

## 前提

### 以下のgemのインストールは済んでいること

- carrierwave
- carrierwave_backgrounder（※インストール方法は、上記参照）
- sidekiq（ActiveJobで利用）

## CarrierWaveの設定

### carrierwaveのgeneratorを使って、対象となるクラスを作成

```
rails generate uploader Image
# -> app/uploaders/image_uploader.rb にファイルが作成される。
```

### 対象のテーブルにカラムを追加する

今回は`products`テーブルに`image:string`を追加する

```
rails g migration add_image_to_products image:string
```

```ruby
class AddImageToProducts < ActiveRecord::Migration[5.2]
  def change
    add_column :products, :image, :string
  end
end
```

### 対象クラスにuploaderを定義する

```ruby:app/models/product.rb
    mount_uploader :image, ImageUploader
```

### uploaderで`move_to_cache`、`move_to_store`を有効にする（任意？）。

```ruby:app/uploaders/image_uploader.rb
  def move_to_cache
    true
  end

  def move_to_store
    true
  end
```

### controllerのparamsに`image`を追加する（割愛）

## CarrierWave Backgrounderの設定

### 対象クラスにbackground処理の設定を行う

```ruby:app/models/product.rb
  process_in_background :image # こちらは任意かも
  store_in_background :image
```

### 対象テーブルに必要なカラムを追加する

```
rails g migration add_image_processing_to_products image_processing:boolean
```

```ruby
class AddImageProcessingToProducts < ActiveRecord::Migration[5.2]
  def change
    add_column :products, :image_processing, :boolean
  end
end
```

```
rails g migration add_image_tmp_to_products image_tmp:string
```

```ruby
class AddImageTmpToProducts < ActiveRecord::Migration[5.2]
  def change
    add_column :products, :image_tmp, :string
  end
end
```

### uploaderにバックグラウンド処理を定義する

```ruby:app/uploaders/image_uploader.rb
  include ::CarrierWave::Backgrounder::Delay 
```

### initializersの生成

```
rails g carrierwave_backgrounder:install
# -> config/initializers/carrierwave_backgrounder.rb が生成される
```

`active_job` を使うように変更する。

```ruby:config/initializers/carrierwave_backgrounder.rb
CarrierWave::Backgrounder.configure do |c|
  # c.backend :delayed_job, queue: :carrierwave
  c.backend :active_job, queue: :carrierwave
  # c.backend :resque, queue: :carrierwave
  # c.backend :sidekiq, queue: :carrierwave
  # c.backend :girl_friday, queue: :carrierwave
  # c.backend :sucker_punch, queue: :carrierwave
  # c.backend :qu, queue: :carrierwave
  # c.backend :qc
end
```

### バックグラウンド処理をするための設定を追加

```ruby:app/models/product.rb
  store_in_background :image, UploadImageJob
```

```ruby:app/models/product.rb
  # 最終的には、以下のような形になっている
  mount_uploader :image, ImageUploader
  process_in_background :image
  store_in_background :image, UploadImageJob
```

### バックグラウンドジョブの設定

```ruby:app/jobs/upload_image_job.rb
class UploadDigitalImageJob < ApplicationJob
  # include ::CarrierWave::Workers::ProcessAssetMixin
  include ::CarrierWave::Workers::StoreAssetMixin
  include RescueFromError
  queue_as :carrierwave

  after_perform do
    # 処理完了後に、メールを送信する
    image = job.record
    UserMailer.notification_uploaded(image).deliver_later
  end
end

```

## 動作確認

### ジョブを実行して、`sidekiq`のログでジョブが正常終了すること、及びファイルがアップロードされていることを確認