[Rails] CarrierWave 経由で AWS S3 にファイルをアップロードする際の設定(ACCESS DENIED の対処)

# 対象者

- いろんな記事を見て回って試しているけど、S3からACCESS DENIED がずっと返って来る。
- 諦めたい

そんな人の助けになれば幸いです...！><

# 使ったもの

```ruby:Gemfile
gem 'rails', '4.2.3'
# CarrierWave
gem 'carrierwave'
gem 'fog-aws'
```

```ruby:Gemfile.lock
carrierwave (1.3.1)
...
fog-aws (3.4.0)
```
でした。

# 概要

~~ACCESS DENIED を解決するために行ったAWS S3設定画像を貼っているだけです←本当にこれだけ~~
ACCESS DENIED を解決するための方法として、AWS S3の設定をいじるのはやめました。
(推奨)マークがついているものは全てチェックを維持したままでも、CarrierWave側のconfigに１行追加すれば ACCESS DENIED を回避できました。

AWSの設定、S3の作成、carrierewaveの設定については、いろんな記事があって私が解説する必要もないので、私が使用した記事を掲載するにとどめます。

# やり方

### AWSの準備、S3バケットの作成
[エラー<Message>Access Denied</Message> 〜Rails + Carrierwave + HerokuでAWS S3に画像を保存〜](https://qiita.com/yukiyukimiyaiwa/items/a9e0103c8342b81f6ac1)

### Railsコードの記述、CarrierWaveの設定
[【Rails5】Carrierwave + Fog で AWS S3 に画像をアップロードする](https://remonote.jp/rails-carrierwave-fog-s3)

### 参考(エラーの対処と、CarrierWaveの設定項目の解説)
[【Rails】AWS S3へ画像のアップロードが出来た♪](https://pg-happy.jp/rails-aws-s3-upload.html)

### 実際に行った設定

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

CarrierWave.configure do |config|
  if Rails.env.production? || Rails.env.development? # 開発中もs3使う
    config.storage :fog
    config.fog_provider = 'fog/aws'
    config.fog_directory  = 'バケット名'
    config.asset_host = 'https://s3.amazonaws.com/バケット名'
    config.fog_credentials = {
      provider: 'AWS',
      aws_access_key_id: 'AWS_ACCESS_KEY_ID',
      aws_secret_access_key: 'AWS_SECRET_ACCESS_KEY',
      region: 'us-east-2',
      # path_style: true
    }
  else
    config.storage :file
    config.enable_processing = false if Rails.env.test?
  end
end
```
```ruby:app/uploaders/hoge_uploders.rb
class HogeUploader < CarrierWave::Uploader::Base
  storage :fog
  def store_dir
    "carrierwave-test-siruku6/uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}"
  end
end
```

# 発生したエラー
```bash:log
Completed 500 Internal Server Error in 6490ms (ActiveRecord: 5.4ms)

Excon::Error::Forbidden (Expected(200) <=> Actual(403 Forbidden)
excon.error.response
  :body          => "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Error><Code>AccessDenied</Code><Message>Access Denied</Message><RequestId>xxxxxxxx</RequestId><HostId>xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx</HostId></Error>"
  :cookies       => [
  ]
  :headers       => {
    "Connection"       => "close"
    "Content-Type"     => "application/xml"
    "Date"             => "Sat, 16 Mar 2019 17:05:27 GMT"
    "Server"           => "AmazonS3"
    "x-amz-id-2"       => "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
    "x-amz-request-id" => "xxxxxxxxxxxxxxxx"
  }
  :host          => "バケット名.s3.us-east-2.amazonaws.com"
  :local_address => "xxx.xxx.xxx.xxx"
  :local_port    => 44250
  :path          => "/xxxxxxxxxxxxxxx/uploads/xxxxxxxx/xxxxxxxxx/1/fx%E6%90%8D%E7%9B%8A.pdf"
  :port          => 443
  :reason_phrase => "Forbidden"
  :remote_ip     => "xxx.xxx.xxx.xxx"
  :status        => 403
  :status_line   => "HTTP/1.1 403 Forbidden\r\n"
):
  app/controllers/hoge_controller.rb:14:in `upload'
```
むぐぐ

# ~~やむを得ず行った変更(AWS S3)~~

![image.png](https://qiita-image-store.s3.amazonaws.com/0/327407/9a455dc9-add0-13a1-7f27-abcdad1a40b8.png)
~~１つチェックを外して設定を保存した~~
セキュリティが落ちるので、**チェックを外すのはやめました**。

# 代替策(設定変更)

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

CarrierWave.configure do |config|
  if Rails.env.production? || Rails.env.development? # 開発中もs3使う
    config.storage :fog
    config.fog_provider = 'fog/aws'
    config.fog_directory  = 'バケット名'
    config.asset_host = 'https://s3.amazonaws.com/バケット名'
    # NOTE: AWS側の設定を変えなくても、この１行の設定でアップロードできた
    config.fog_public = false # ←コレ
    config.fog_credentials = {
      provider: 'AWS',
      aws_access_key_id: 'AWS_ACCESS_KEY_ID',
      aws_secret_access_key: 'AWS_SECRET_ACCESS_KEY',
      region: 'us-east-2',
      # path_style: true
    }
  else
    config.storage :file
    config.enable_processing = false if Rails.env.test?
  end
end
```
これでアップロードできた！

#### 参考にしたサイト

[【Ruby on Rails】carrierwave-awsを使ってAWSのS3に画像をアップロードするときにAws::S3::Errors::AccessDeniedのエラー対処法](https://y-hilite.com/3204/)
この人はチェック３つ外してるけど、一番上の１つだけでも動いたよ。

#### その他

stackoverflowにはこんなこと書かれてるけど、これは試してないです
[Excon::Errors::Forbidden (Expected(200) <=> Actual(403 Forbidden)](https://stackoverflow.com/questions/28564653/exconerrorsforbidden-expected200-actual403-forbidden)

# 考えたこと

- 「パブリックオブジェクトのアップロードをブロックする」という設定が有効
- config.fog_public = true または config.fog_public を設定していない

この２つの条件を両方満たすと、403エラーになるようだ。
fog_publicというのは、パブリックオブジェクトとしてアップロードするかどうかの設定だったみたい。