【Rails】Carrierwaveを用いてAWSのS3にPDFのアップロードとダウンロードを可能にする。

# はじめに
<p>PDF投稿機能。cloudinaryではpdfに対応していないので、AWSのS3を使ってPDF投稿を実現しました。</p>

# 開発環境
- Ruby 3.0.4
- Rails 6.1.7

# 前提
- tweetsコントローラーで投稿機能作成済み
- tweetsテーブルにはpdfカラムstringで用意
- [AWSアカウント登録済](https://aws.amazon.com/jp/free/?gclid=Cj0KCQjwqoibBhDUARIsAH2OpWjwD6i56zlT62LqzwhLLLs-Pwqdqo91PMZ_10Pre8KXy7wURDGgIOkaAuJXEALw_wcB&trk=94c18984-27d1-4395-8dae-cdbf523f1ae5&sc_channel=ps&s_kwcid=AL!4422!3!568105078079!e!!g!!aws&ef_id=Cj0KCQjwqoibBhDUARIsAH2OpWjwD6i56zlT62LqzwhLLLs-Pwqdqo91PMZ_10Pre8KXy7wURDGgIOkaAuJXEALw_wcB:G:s&s_kwcid=AL!4422!3!568105078079!e!!g!!aws&all-free-tier.sort-by=item.additionalFields.SortRank&all-free-tier.sort-order=asc&awsf.Free%20Tier%20Types=*all&awsf.Free%20Tier%20Categories=*all)


# 目次
1. [AWSの設定](#Chapter1)
1. [PDFをS3にアップロードできるようにする](#Chapter2)
1. [S3からPDFをダウンロードできるようにする](#Chapter3)
1. [参考文献](#reference)

<!-- 各チャプター -->
<a id="#Chapter1"></a>
# AWSの設定
### ①IAMユーザーとS３バケットの作成
AWSを利用するための、IAMユーザーの作成と、S3バケットの作成は[こちらの記事](https://qiita.com/mattan5271/items/96721426cff2b1d67cdd)がわかりやすいので、参考にしてください。

:::note 
S3を利用するにはIAMユーザーの作成が必要です。
IAMユーザーを作成した際のアクセスキーとシークレットアクセスキーが後に必要なので、.cnvファイルをダウンロードし、保管しておいてください。
:::
### ②バケットポリシーの追加
[上の記事](https://qiita.com/mattan5271/items/96721426cff2b1d67cdd)の16.バケットの作成までできたら、バケットにポリシーを追加します。
①AWSの自分のアカウントにログインし、 **S3>バケット**を開く。
②自分のバケットの名前（リンクになっている部分）をクリック
③ **アクセス許可**を選択し、 **バケットポリシーの編集**をクリック
④以下のようにポリシーを変更し、保存

 ```aws:バケットポリシー
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": {
                "AWS": "*******************①**********************"
            },
            "Action": "s3:ListBucket",
            "Resource": "arn:aws:s3:::*******②*******"
        }
    ]
}
```
※①にはIAMのAWS、②にはS3のバケット名が入ります

:::note 
IAMのAWSの確認は、 **IAM>ユーザー**へ行き、ユーザーの名（リンクになっている部分）をクリックすると確認できます。
例：arn:aws:iam::123456789123:user/hoge_user
:::

<a id="#Chapter2"></a>
# PDFをS3にアップロードできるようにする
### 準備,Gemのインストール
 ```ruby:Gemfile
gem 'dotenv-rails' 
gem 'fog-aws'
gem 'carrierwave'
```
コマンドプロンプト（ターミナル）で``` bundle install```を実行
### ①キーを環境変数化
#### 1,`.env`ファイルの作成
①`.env`というファイルを アプリケーションディレクトリ(appやdbやGemfileがあるディレクトリ) に自分で作成
②IAMユーザーを作成した際のアクセスキーとシークレットアクセスキーを参照し、以下を変更
```ruby:.env
SECRET_ACCESS_KEY=p2g456789qwertyuiopasdfghjklzxcvbnm01234  #←自分のキーを入力
ACCESS_KEY_ID=ASDFGHJKL12ASDFGHJK  #←自分のキーを入力
```
#### 2,`.gitignore`の変更
```ruby:gitignore
/.env
```
### ②Uploaderの作成と設定
#### 1,uploaderの作成
```:コマンドプロンプト
$ rails generate uploader UploadPdf
$ rails generate model UploadPdf pdf:string
```
#### 2,Tweetモデルにpdfカラムのuploaderを指定
```ruby:mopdels/tweet.rb
class Tweet < ApplicationRecord
    mount_uploader :pdf, UploadPdfUploader
end
```
#### 3,uploaderの変更
storage :fileをコメントアウトし、storage :fogのコメントアウトを外して有効にする
```ruby:uploaders/upload_pdf_uploader.rb
  #storage :file
  storage :fog
```

### ②carrierwaveの作成と設定
#### 1,initializersフォルダ内にcarrierwaveファイルの作成

```:コマンドプロンプト
$ type nul > config/initializers/carrierwave.rb
```
※Macではtouchで実行できる
#### 2,carrierwaveファイルの変更
バケット名は自分のものに変更してください。
```ruby:initializers/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  = 'nacchi-test-aws' # バケット名
    config.fog_public = false
    config.fog_credentials = {
      provider: 'AWS',
      aws_access_key_id: ENV['ACCESS_KEY_ID'], # アクセスキー
      aws_secret_access_key: ENV['SECRET_ACCESS_KEY'], # シークレットアクセスキー
      region: 'ap-northeast-1', # リージョン
      path_style: true
    }
end
```
### ④PDFの表示（view）
```ruby:tweets/index.html
  <% @tweets.each do |t| %>
    <div class="tweet">
      <%= t.id %>
      <%= t.body %>
      <%= t.pdf %>
      <object data=<%= t.pdf %> type="application/pdf" width="250" height="200"></object>
      <%= t.created_at %>
    </div>
  <% end %>
```

<a id="#Chapter3"></a>
# S3からPDFをダウンロードできるようにする
### ①ルーティングの設定
```ruby:routes.rb
  get 'tweeets/download/:id',to: "tweets#download",as: "download_pdf"
```
### ①コントローラーの編集
```ruby:tweets_controller.rb
  def download
    @tweet = Tweet.find(params[:id])
    send_data(@tweet.pdf.read,:filename => @tweet.pdf_identifier, :type => "application/pdf")
  end
```
### ①viewの編集
```ruby:tweets/index.html.erb
  <% @tweets.each do |t| %>
    <div class="tweet">
    <%= t.id %>
    <%= t.body %>
      <%= t.pdf %>
     <object data=<%= t.pdf %> type="application/pdf" width="250" height="200"></object>
     <%= link_to 'ダウンロード',download_pdf_path(t.id) %> #追記
      <%= t.created_at %>
    </div>
  <% end %>
```



<a id="#reference"></a>
# 参考文献
- [【Rails】Carrierwaveとfog-awsを用いて、画像をAWS S3へアップロードする方法](https://qiita.com/mattan5271/items/96721426cff2b1d67cdd)
- [Rails でファイルのアップロードとダウンロード](https://www.ccbaxy.xyz/blog/2019/11/18/ruby15/)

# 最後に
初めてQiitaで記事を投稿しました。誤り、改良点がありましたら教えていただけると嬉しいです。