CarrierWaveによるRails ファイルアップロード

CarrierWaveと<a href="https://qiita.com/ebi_ebi/items/260be781987284bf3866">Active Storage</a>でのファイルアップロードの説明を書きます。
この記事はCarrierWaveになります。

## 前提
AWSアカウント作成済み
IAMユーザのアクセスキーを取得済み
S3のバケット作成済み

## 環境
ruby  2.5.1
rails 5.2.2

## githubでソースを公開しています。
https://github.com/ebi5714/carrierwave

## 手順
### gemを追加

```ruby:Gemfile
gem "figaro", "~> 1.1.1"
gem 'carrierwave'
gem 'fog'
gem "mini_magick"
```

figraro:     環境変数を設定するgem
carrierwave: ファイルアップロードのgem
fog:         S3にアップロードする為に必要なgem
mini_magick: 画像をリサイズする為に必要なgem

```shell
$ bundle install --path vendor/bundler
```

### アップローダーの作成
```shell
$ bundle exec rails g uploader Image
```
画像のリサイズをする為にMiniMagickをincludeしています。
S3にアップロードする為にstorageは:fogを指定しています。

```ruby:image_uploader.rb
class ImageUploader < CarrierWave::Uploader::Base
  include CarrierWave::MiniMagick

  # envで分けたい時、developmentはfile、それ以外はfogを使う
  # storage if Rails.env.development? ? :file : :fog
  storage :fog

  def store_dir
    "uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}"
  end

  process resize_to_fit: [150, 150]

  def extension_whitelist
    %w(jpg jpeg gif png)
  end
end
```

### モデルの作成

```shell
$ bundle exec rails g model picture
```
マイグレーションファイルが作成されます、imageカラムを追加します。

```ruby:20190106050728_create_pictures.rb
class CreatePictures < ActiveRecord::Migration[5.2]
  def change
    create_table :pictures do |t|
      t.string :image
      t.timestamps
    end
  end
end
```

### マイグレーションの実行

```shell
$ bundle exec rake db:migrate
```

### pictureモデルにアップローダーを紐付ける

```ruby:app/models/picture.rb
class Picture < ApplicationRecord
  mount_uploader :image, ImageUploader
end
```

### carrierwaveの設定
ここでaccess_keyやsecret_access_key,backet名は
application.ymlに設定しています(figraroのgem)
application.ymlにはaccess_keyなどが記載されていますので
.gitignoreに追記をします。

```ruby:.gitignore
# Ignore application configuration
/config/application.yml
```

```ruby:config/application.yml
AWS_ACCESS_KEY_ID: "○○○○"
AWS_SECRET_ACCESS_KEY: "○○○○"
AWS_BUCKET: "○○○○"
DATABASE_USERNAME: "root"
DATABASE_PASSWORD: ""
```

```ruby:config/initializers/carrierwave.rb
CarrierWave.configure do |config|
  config.fog_credentials = {
    provider: 'AWS',
    aws_access_key_id: ENV["AWS_ACCESS_KEY_ID"],
    aws_secret_access_key: ENV["AWS_SECRET_ACCESS_KEY"],
    region: 'ap-northeast-1'
  }

  config.fog_directory  = ENV["AWS_BUCKET"]

  config.cache_storage = :fog
end
```

### コントローラーやViewの作成

```shell
$ bundle exec rails g scaffold_controller pictures 
```

コントローラーはpermitにimageを追加します。

```ruby:app/controllers/pictures_controller.rb
class PicturesController < ApplicationController
  before_action :set_picture, only: [:show, :edit, :update]

  # GET /pictures
  def index
    @pictures = Picture.all
  end

  # GET /pictures/1
  def show
  end

  # GET /pictures/new
  def new
    @picture = Picture.new
  end

  # GET /pictures/1/edit
  def edit
  end

  # POST /pictures
  def create
    @picture = Picture.new(picture_params)

    respond_to do |format|
      if @picture.save
        format.html { redirect_to @picture, notice: 'Picture was successfully created.' }
      else
        format.html { render :new }
      end
    end
  end

  # PATCH/PUT /pictures/1
  def update
    respond_to do |format|
      if @picture.update(picture_params)
        format.html { redirect_to @picture, notice: 'Picture was successfully updated.' }
      else
        format.html { render :edit }
      end
    end
  end

  private
    # Use callbacks to share common setup or constraints between actions.
    def set_picture
      @picture = Picture.find(params[:id])
    end

    # Never trust parameters from the scary internet, only allow the white list through.
    def picture_params
      params.fetch(:picture, {}).permit(:image)
    end
end
```

### アップロード

```:app/views/pictures/_form.html.erb
<%= form.file_field :image %>
```

### 画像表示
```:app/views/pictures/index.html.erb
<%= image_tag picture.image.to_s %>
```