CarrierWave + carrierwave-aws で aws-sdk-s3 にオプションを渡す

いろいろなことがあり、 CarrierWave とそのストレージライブラリである carrierwave-aws を読んでたのでメモ。主に carrierwave-aws の話。

前提

AWS SDK for Ruby のライブラリのバージョン探すの大変だよね。


つまるところ

例えばアプリケーションで以下のようにCarrierWaveのアップローダーを作ると、S3へのアップロード時にマルチパートアップロードを使用するか判断するファイルサイズの閾値aws-sdk-s3 v1.98.0 時点でのデフォルトである 100MB から変更できる。

class FooUploader < CarrierWave::Uploader::Base
  storage :aws
  
.....

  def aws_write_options
    { multipart_threshold: 20.megabyte }
  end
end

どうなってんの

このライブラリ、 README にはぱっとみ書いてないんだけど CarrierWave::Uploader::Base を継承した uploaderに aws_write_options というメソッドを定義して、ハッシュを渡すと uploader.aws_write_options で読み込んでくれる。このオプションはアップロード時に CarrierWave::Storage::AWSFile#store` で aws-sdk-s3 に渡される。

carrierwave-aws/aws_options.rb at v1.5.0 · carrierwaveuploader/carrierwave-aws · GitHub

      def aws_write_options
        uploader.aws_write_options || {}
      end

ここで定義したアップローダーのオプションを読み込んでくれる

carrierwave-aws/aws_options.rb at v1.5.0 · carrierwaveuploader/carrierwave-aws · GitHub

      def write_options(new_file)
        {
          acl: uploader.aws_acl,
          body: new_file.to_file,
          content_type: new_file.content_type
        }.merge(aws_attributes).merge(aws_write_options)
      end

CarrierWave::Storage::AWSOptions#write_options で読み込んだオプションはここでマージされる

carrierwave-aws/aws_file.rb at v1.5.0 · carrierwaveuploader/carrierwave-aws · GitHub

      def store(new_file)
        if new_file.is_a?(self.class)
          new_file.move_to(path)
        else
          file.upload_file(new_file.path, aws_options.write_options(new_file))
        end
      end

file.upload_file で↑の write_options を渡してますね。

aws-sdk-ruby/file_uploader.rb at c1f4ac742f4dbb66203cc10c45af0019f98b8fde · aws/aws-sdk-ruby · GitHub

aws-sdk-s3 では渡したオプションが Aws::S3::FileUploader コンストラクタ引数の options に入ってくる。という感じ。

      def initialize(options = {})
        @options = options
        @client = options[:client] || Client.new
        @multipart_threshold = options[:multipart_threshold] ||
                               ONE_HUNDRED_MEGABYTES
      end

このあと読む

実はもっとシンプルな指定ができるんじゃないの?ってのが気になってるのでそのとっかかりをメモっとく

carrierwave-aws/carrierwave-aws.rb at v1.5.0 · carrierwaveuploader/carrierwave-aws · GitHub このオプションは add_config で同名のシンボルを引数に渡してそう。

carrierwave/configuration.rb at a3ffc5381e70a4014b61b27b35540aa3b945910d · carrierwaveuploader/carrierwave · GitHub CarrierWave 本体で定義されているメソッドなので、ここらへんでなんやかんやしてそう。