Heroku上の画像をAWSのS3へ保存する方法

# はじめに
AWSはAmazon Web Servisesの略で、Amazonが提供しているクラウドサーバーのサービスです。
多くの人や企業で使用されているサービスであり、使う容量や期間によっては完全に無料で使うことができます。


# Heroku上の画像をAWSに保存する理由
Herokuに保存した画像は24時間に一度リセットされる仕様になっています。
画像を外部のサーバーに保存することで、画像が消えてしまうという現象を防ぐことができるため、今回は外部サーバーとしてAWSを利用します。


# S3とは

AWSのサービスの一つで、12ヶ月間、5GBまでのストレージを無料で利用することができるサービスで、画像などを保存しておくことができます。

# 今回の手順
AWSへの登録はできている前提で進めます。（登録していない方はAWSで検索して、新規登録してください。）

* IAMユーザーを作成する
* S3に画像の保存先を用意する
* ローカル環境で画像の保存先をS3に変更する
* 本番環境で画像の保存先をS3に変更する


# IAMユーザーを作成する

### IAMとは

IAMとはAWSのサービスの一つです。
AWSで作成したアカウントはすべての権限を持つルートユーザーとなり、万が一、情報漏洩してしまうと悪用されてしまうリスクがあります。
そのため、使える権限を制限したユーザーを作成し、通常の作業はそのユーザーで行うようにします。
その制限された権限を持つユーザーを作成する機能を持つのがIAMです。


### IAMユーザーの作成
IAMで作成されるユーザーをIAMユーザーと呼びます。
まず、AWSのサービス検索でIAMを検索し、IAMページへ遷移します。
サイドバーのユーザーから「ユーザーを追加」をクリックします。
そして、任意のユーザー名を入力し、プログラムによるアクセスにチェックを入れ、「次のステップ」をクリックします。
既存のポリシーを直接アタッチを選択し、ポリシーのフィルタにamazons3と入力し、、「AmazonS3FullAccess」にチェックを入れ、「次のステップ」をクリックします。
タグの追加はやりたい人のみやって、「次のステップ」をクリックします。
設定の確認画面が出るので、問題なければ「ユーザーの作成」をクリックします。
この時に出てくる「.csvのダウンロード」は忘れずに、行います。（後々、使うため。）


### IAMユーザーのパスワードを設定

上で作成したAWS上のIAMユーザーの中で、認証情報のタブをクリックすると、コンソールのパスワード欄があります。
ここの管理をクリックした後に出てくるページで、コンソールへのアクセスは有効化、パスワードの設定は自動生成パスワードを選択し、適用します。
そうすると、パスワードが生成されます。
この時に出てくる「.csvのダウンロード」は忘れずに、行います。（後々、使うため。）


# S3に画像の保存先を用意する

### バケットの作成

S3で実際にデータが格納される場所のことをバケットと呼びます。
AWSにログイン後、サービス検索でS3のページに遷移すると、バケットという文字が出てきます。
サイドバーのバケットという項目の中には「バケットを作成する」というボタンが存在するので、そのボタンをクリックします。

### バケット名とリージョンの設定

バケット名とリージョンの入力画面に遷移するため、自身で考えたバケット名を入力します。
※バケット名はAWSを使う誰かのバケットと同じ名前はつけられません。

リージョンは地域という意味ですが、ここではサーバーの場所を表します。
日本人ならアジアパシフィック(東京)を選択で良いと思います。


### オプションの設定

オプションを設定したい方はここで設定します。
設定が終われば、次へをクリックします。


### アクセス許可の設定

デフォルトでは「パブリックアクセスをすべてブロック」にチェックが入っています。
このチェックを外すと、パブリックアクセスのお好みの設定ができます。
設定が終われば、次へをクリックします。

### 確認

確認ページではこれまで行った設定の一覧が表示されるので、問題なければ、「バケットを作成」をクリックします。


### バケットポリシーの設定

バケットポリシーとは、どのようなアクセスに対してS3への保存やデータの読み取りを許可するか決められる仕組みです。
今回は先ほど作成したIAMユーザーからのアクセスを許可します。

まず、IAMユーザーのARNをコピーして、どこかにメモしておきます。

作成したバケットから、アクセス権限をクリックし、バケットポリシーをクリックし、以下を記述します。

```
{
   "Version": "2012-10-17",
   "Id": "Policy1544152951996",
   "Statement": [
       {
           "Sid": "Stmt1544152948221",
           "Effect": "Allow",
           "Principal": {
               "AWS": "コピーしたIAMユーザーのARN"
           },
           "Action": "s3:*",
           "Resource": "arn:aws:s3:::バケット名"
       }
   ]
}
```

保存すれば、完了です。



# ローカル環境で画像の保存先をS3に変更する

### Gemのインストール

rubyでS3を使用するためにaws-sdk-smというGemをインストールします。

```ruby:Gemfile
一番下に下記を追記
gem "aws-sdk-s3", require: false
```
その後、ターミナルでbundle installを入力します。

### 保存先を指定する

```ruby:config/environments/development.rb
config.active_storage.service = :local

上の記述を以下に変更

config.active_storage.service = :amazon
```

```yml:config/storage.yml

以下のコードを追記

amazon:
 service: S3
 access_key_id: <%= ENV['AWS_ACCESS_KEY_ID'] %>
 secret_access_key: <%= ENV['AWS_SECRET_ACCESS_KEY'] %>
 region: ap-northeast-1
 bucket: ご自身のバケット名
```
※regionのap-northease-1はアジアパシフィック(東京)の番号

### 環境変数の設定

```terminal:ターミナル
% vim ~/.zshrc

iを押して、以下を追記

export AWS_ACCESS_KEY_ID="ここにCSVファイルのAccess key IDの値をコピー"
export AWS_SECRET_ACCESS_KEY="ここにCSVファイルのSecret access keyの値をコピー"
（CSVファイルはIAMユーザー作成時にダウンロードしたファイルのこと。）

:wqで保存する
```

ローカル環境で、アプリケーションから画像を投稿し、問題なくS3に保存されていることが確認できたら、本番環境でも画像の保存先をS3に変更します。

# 本番環境で画像の保存先をS3に変更する

### 保存先を指定する

ローカル環境と同様の作業を行います。

```ruby:config/environments/production.rb
config.active_storage.service = :local

上の記述を以下に変更

config.active_storage.service = :amazon
```

### 環境変数の設定
本番環境にはHerokuを用いるため、Heroku上で環境変数を設定します。
heroku config:setコマンドで環境変数の設定をすることができます。

```terminal:ターミナル
% heroku config:set AWS_ACCESS_KEY_ID="ここにCSVファイルの「Access key ID」の値をコピー"
% heroku config:set AWS_SECRET_ACCESS_KEY="ここにCSVファイルの「Secret access key」の値をコピー"

環境変数が設定できたか確認するときは
% heroku config
```

### 編集内容をHerokuに反映させる

```terminal:ターミナル
% git push heroku master
```


# 参考
テックキャンプのカリキュラム
「AWSに画像をアップロードする」

# 最後に
本投稿が初学者の復習の一助となればと幸いです。