💩

【Rails】S3 × CarrierWave × fog-aws で画像アップロード

2022/05/27に公開

Railsアプリで、画像を AWS S3にアップロードします。
dotenvを用いて .envを用いる方法が多かったですが、個人的に credentials を用いていたのでそちらの実装です。

前提

  • AWS S3でバケットが作成されている
  • CarrierWave導入済み

実装

fog-awsをインストール

gem 'fog-aws'

uploaderfogの使用を記述する。

/uploaders/board_image_uploader.rb
class BoardImageUploader < CarrierWave::Uploader::Base
  # Include RMagick or MiniMagick support:
  # include CarrierWave::RMagick
  # include CarrierWave::MiniMagick

  # Choose what kind of storage to use for this uploader:
  # ここで設定
  # productionでは、fogで外部ストレージにアップロードする
  if Rails.env.development? || Rails.env.test?
    storage :file
  else
    storage :fog
  end

  # Override the directory where uploaded files will be stored.
  # This is a sensible default for uploaders that are meant to be mounted:
  def store_dir
    "uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}"
  end

  # Provide a default URL as a default if there hasn't been a file uploaded:
  # def default_url(*args)
  #   # For Rails 3.1+ asset pipeline compatibility:
  #   # ActionController::Base.helpers.asset_path("fallback/" + [version_name, "default.png"].compact.join('_'))
  #
  #   "/images/fallback/" + [version_name, "default.png"].compact.join('_')
  # end

  # Process files as they are uploaded:
  # process scale: [200, 300]
  #
  # def scale(width, height)
  #   # do something
  # end

  # Create different versions of your uploaded files:
  # version :thumb do
  #   process resize_to_fit: [50, 50]
  # end

  # Add an allowlist of extensions which are allowed to be uploaded.
  # For images you might use something like this:
  def extension_allowlist
    %w[jpg jpeg gif png]
  end

  def size_range
    0..20.megabytes
  end

  # Override the filename of the uploaded files:
  # Avoid using model.id or version_name here, see uploader/store.rb for details.
  # def filename
  #   "something.jpg" if original_filename
  # end

  def filename
    "#{secure_token(10)}.#{file.extension}" if original_filename.present?
  end

 # 一意となるトークンを作成
  protected
  def secure_token(length=16)
    var = :"@#{mounted_as}_secure_token"
    model.instance_variable_get(var) or model.instance_variable_set(var, SecureRandom.hex(length/2))
  end
end

CarrierWaveを設定する
こちらを参考にしています。
コードの意味が載っており、わかりやすかったです。

config/initializers/carrierwave.rb
require 'carrierwave/storage/abstract'
require 'carrierwave/storage/file'
require 'carrierwave/storage/fog'

# 保存先の分岐
CarrierWave.configure do |config|
  # 本番環境はS3に保存
  if Rails.env.production?
    config.storage = :fog
    config.fog_provider = 'fog/aws'
    config.fog_directory  = 'inspigram-image-store'
    config.asset_host = 'https://s3-ap-northeast-1.amazonaws.com/inspigram-image-store'
    # iam_profile
    config.fog_credentials = {
      provider: 'AWS',
      # credentialsで管理
      aws_access_key_id: Rails.application.credentials.aws[:access_key_id],
      aws_secret_access_key: Rails.application.credentials.aws[:secret_access_key],
      region: 'ap-northeast-1' #東京リージョン
    }
    # キャッシュをS3に保存
    # config.cache_storage = :fog
  else
    # 開発環境はlocalに保存
    config.storage :file
    config.enable_processing = false if Rails.env.test? #test:処理をスキップ
  end  
end

credentialsの編集を行う
ターミナルにて以下のコマンドを打ちます。

EDITOR="vi" bin/rails credentials:edit

以下の形式で、ファイルを編集します。
インデントや空白に注意してください。
正しく読み込まれなくなる場合があります。

aws:
  access_key_id: barbarbarbar
  secret_access_key: foofoofoofoo

Discussion