【初学者必見】 HerokuとAWS S3を連携して投稿画像を保持する方法

Rails初学者なら必ずと言っていいほどデプロイで使用するHeroku
**🚨 <font color="OrangeRed">実は作成したアプリからHerokuに投稿した画像は保持されず、一定期間経つと消えてしまいます</font>🚨**
今回はRailsアプリ（CarrierWave）から投稿した画像をS3に保存して消えないようにする方法を超丁寧に解説します！

<br>

## やりたいこと
Herokuにデプロイした画像投稿機能付き掲示板アプリで、ユーザーが投稿した画像をAWS S3に保存して、一定時間経過しても画像が消えないようにしたい。

<br>

## 開発環境 ＆ 前提条件
Ruby 3.0.1
Rails 6.1.4.1
CarrierWaveで画像投稿機能実装済み
Heroku登録済み
サンプルアプリ：[【投票制】マンガ・アニメランキング](https://anime-manga-ranking.herokuapp.com/)

<br>


## おおまかな手順
1. AWS関係の設定
1. CarrierWaveの設定
1. Herokuの設定

こちらを超丁寧に8ステップに切り分けて解説します🌿

<br>


## ステップ１：AWS関係の登録
まずは[こちら](https://aws.amazon.com/jp/register-flow/)のAmazon公式手順の通りにAWSアカウントを作成します。
<font color="DodgerBlue">AWSとは？
→ Amazon Web Serviceの略。クラウド上でAmazonが提供するデータベースや機械学習などのサービス
</font>
アカウントを作成したら、[こちら](https://qiita.com/nobu0717/items/4425c02157bc5e88d7b6)の記事の通りにIAMアカウントとS3バケットを作成します。
<font color="DodgerBlue">IAMとは？
→ Identity and Access Managementの略。AWSのIDやアクセス権を管理するサービス
</font>
<font color="DodgerBlue">S3とは？
→ Amazon Simple Storage Serviceの略。AWSが提供するオンラインストレージサービス
</font>

<br>
<br>


## ステップ２：AWS用のgemをインストール
<font color="OrangeRed">Gemfile</font>のグローバルにgemの追記をして、<font color="OrangeRed">bundle install</font>します。


```ruby:Gemfile
gem 'fog-aws'
gem "aws-sdk-s3", require: false 
```

<br>
<br>


## ステップ３：uploaderファイルの編集
carrierwave導入時に作成される <font color="OrangeRed">app/uploaders/○○○_uploader.rb</font> ファイルに指定されている画像のストレージ先を変更します。

```ruby:○○○_uploader.rb
# storage :file から以下に変更
storage :fog
```

<br>

開発環境ごとに保存先を変えたい場合は、以下のようにすると本番環境でのみS3への保存ができます！

```ruby:○○○_uploader.rb
if Rails.env.development?
  storage :file
elsif Rails.env.test?
  storage :file
else
  storage :fog
end
```

<br>
<br>

## ステップ４：carrierwaveファイルの作成＆編集
<font color="OrangeRed">app/config/initializers直下</font>に<font color="OrangeRed">carrierwave.rb</font>ファイルを作成して、以下の通りに編集していきます。
'S3のバケット名'をご自身のものにするのを忘れないようにしてください！
ENV['AWS_ACCESS_KEY_ID']などの環境変数の使用についてはステップ５で解説します。

```ruby:carrierwave.rb
require 'carrierwave/storage/abstract'
require 'carrierwave/storage/file'
require 'carrierwave/storage/fog'

CarrierWave.configure do |config|
  config.storage :fog
  config.fog_provider = 'fog/aws'
  config.fog_directory  = 'S3のバケット名'
  config.fog_credentials = {
    provider: 'AWS',
    aws_access_key_id: ENV['AWS_ACCESS_KEY_ID'],
    aws_secret_access_key: ENV['AWS_SECRET_ACCESS_KEY'],
    region: ENV['AWS_DEFAULT_REGION'],
    path_style: true
  }

end
```

<br>
<br>


## ステップ５：storage関連ファイルの編集
以下の２つのファイルにaws関連の記述を追加します！
```yml:config/storage.yml
# コメントアウトを外す。
amazon:
  service: S3
  access_key_id: <%= Rails.application.credentials.dig(:aws, :access_key_id) %>
  secret_access_key: <%= Rails.application.credentials.dig(:aws, :secret_access_key) %>
  region: ap-northeast-1 #東京に修正
  bucket: S3のバケット名 #作成したS3のバケットの名前
```
```ruby:config/environments/production.rb
# localからamazonに修正
config.active_storage.service = :amazon
```



<br>
<br>



## ステップ6：環境変数の設定
<font color="DodgerBlue">
環境変数とは？
→ 簡単に言うと、ネット上に公開させたくない情報を入れておく箱のことです。
</font>
carrierwave.rbに直接AWSのアクセスキーなどを入れることは、セキュリティ上好ましくないのでgemを導入して環境変数を設定します。
<font color="OrangeRed">Gemfile</font>のグローバルに、環境変数を管理できるgemの<font color="OrangeRed">dotenv-rails</font>を追記して、<font color="OrangeRed">bundle install</font>します。

```ruby:Gemfile
gem 'dotenv-rails'
```

<br>

続いて、環境変数を記載するファイルである<font color="OrangeRed">.env</font>を<font color="OrangeRed">app直下</font>に作成して、そちらに必要な環境変数を設定していきます。

```ruby:.env
AWS_ACCESS_KEY_ID='AWSで作成したアクセスキーのID'
AWS_SECRET_ACCESS_KEY='AWSで作成したシークレットアクセスキー'
AWS_DEFAULT_REGION='ap-northeast-1'
```

<br>

最後に、.envファイルがネット上にアップされないようにapp直下の<font color="OrangeRed">.gitignore</font>に設定を追加します。

```ruby:.gitignore
# 最終行辺りに.envを追記
/.env
```

<br>
<br>


## ステップ7：Herokuの設定
HerokuにAWSの情報を設定します。

```terminal:terminal
# Herokuへログイン
% heroku login

# Herokuに環境変数を設定
% heroku config:set AWS_ACCESS_KEY_ID="AWSで作成したアクセスキーのID"
% heroku config:set AWS_SECRET_ACCESS_KEY="AWSで作成したシークレットアクセスキー"
% heroku config:set AWS_DEFAULT_REGION="ap-northeast-1"
```

<br>
<br>


## ステップ8：最終確認
ここまでできたら、Herokuにデプロイしましょう！
アプリで画像付きの投稿をすると、S3のバケットに画像がアップロードされます！（画像の赤枠部分）
![名称未設定のデザイン-12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2274644/3f38fc4f-a7ae-d886-f1e2-06d6a42f4913.png)



<br>
<br>

## 最後に
最後まで拝読してくださりありがとうございました！！！
今回の記事が多くの初学者の方のお役に立つことを願っています🌿


<br>

## 参考記事
[Railsでcarrierwaveを使ってAWS S3に画像をアップロードする手順を画像付きで説明する](https://qiita.com/junara/items/1899f23c091bcee3b058)
[【Rails】 dotenv-railsを使って環境変数を管理しよう](https://pikawaka.com/rails/dotenv-rails)