Last Update: 2023-07-30 18:26:06 +0200

title: Shrine 2.13.0

New features

  • The S3 object URLs can now be signed with a custom signer. This enables serving private objects via AWS CloudFront by signing the URLs with the signer from the aws-sdk-cloudfront gem.

require "aws-sdk-cloudfront"

signer = Aws::CloudFront::UrlSigner.new(
  key_pair_id:      "cf-keypair-id",
  private_key_path: "./cf_private_key.pem",

Shrine::Storage::S3.new(signer: signer.method(:signed_url))
  • To make your S3 storage public, previously you needed to do two things: set the acl: "public-read" upload option and set pass public: true when generating a URL.

Shrine.storages = {
  cache: Shrine::Storage::S3.new(upload_options: { acl: "public-read" }, **options),
  store: Shrine::Storage::S3.new(upload_options: { acl: "public-read" }, **options),

Shrine.plugin :default_url_options,
  cache: { public: true },
  store: { public: true }

Now you can achieve the same thing just by setting public: true when initializing the S3 storage.

Shrine.storages = {
  cache: Shrine::Storage::S3.new(public: true, **options),
  store: Shrine::Storage::S3.new(public: true, **options),
  • The :force option has been added to the infer_extension plugin, which makes the extension always determined from the MIME type, regardless of whether it exists or not.

Shrine.plugin :infer_extension, force: true

This is useful for when you want to normalize the file extensions of uploaded files.

uploader.upload(File.open("image.jpg"))  #
uploader.upload(File.open("image.jpeg")) # all these will be uploaded with a .jpeg extension
uploader.upload(File.open("image.JPG"))  #
  • Shrine#upload now accepts a :metadata option for manually overrding the extracted metadata.

uploaded_file = uploader.upload(file, metadata: { "filename" => "my-file.txt" })
uploaded_file.original_filename    #=> "my-file.txt"

Furthermore, Shrine::Attacher#assign now forwards any additional options to Shrine#upload, so you can also override metadata when attaching files.

photo.image_attacher.assign(file, metadata: { "mime_type" => "text/plain" })

Other improvements

  • It’s now possible to use an S3 endpoint which requires bucket name to be in the URI path (e.g. Minio) with CDNs where bucket name shouldn’t be in the URI path (e.g. CloudFront). Since version 2.11.0, when initializing Shrine::Storage::S3 with :endpoint with :force_path_style, generating an URL with a :host returned an URI with bucket name in the path. This introduced a regression for anyone relying on previous behaviour, so that change has been reverted, and this is the current behaviour:

s3 = Shrine::Storage::S3.new(endpoint: "https://minio.example.com")
s3.url("foo")                                     #=> "https://my-s3-endpoint.com/foo"
s3.url("foo", host: "https://123.cloudfront.net") #=> "https://123.cloudfront.net/foo"

s3 = Shrine::Storage::S3.new(endpoint: "https://my-s3-endpoint.com", force_path_style: true, **options)
s3.url("foo")                                     #=> "https://my-s3-endpoint.com/my-bucket/foo"
s3.url("foo", host: "https://123.cloudfront.net") #=> "https://123.cloudfront.net/foo"
  • The :host option to Shrine::Storage::S3#url now handles URLs with path prefixes, provided that the URL ends with a slash.

# old behaviour
s3.url("foo", host: "https://example.com/prefix/") #=> "https://example.com/foo"
# new behaviour
s3.url("foo", host: "https://example.com/prefix/") #=> "https://example.com/prefix/foo"
  • Fixed error that would happen when uploading a file with a filename that had certain combination of UTF-8 characters to upload_endpoint.

  • The Content-Type header in upload_endpoint and presign_endpoint responses now specifies charset=utf-8.

  • Shrine::Storage::S3 now uses Aws::S3::Object#upload_stream if available when uploading large IO streams which are not file objects, which uses parallelized multipart upload. This can make such uploads finish up to 2x faster.

  • Shrine::Storage::S3 now uses Aws::S3::Object#upload_stream if available when uploading files of unknown size.

  • The file command could sometimes exit successfully, but return a cannot open: No such file or directory on stdout. This is now detected and a Shrine::Error is raised.

  • The upload_endpoint now returns Upload Not Valid error message when file parameter was present but not in correct format (previously Upload Not Found was returned, which was a bit misleading).

Backwards compatibility

  • When Shrine::Storage::S3 is initialized with :endpoint with :force_path_style, a file URL generated with a :host will not include the bucket name in the URL path anymore. Users relying on this behaviour should update their code to include the bucket name in the :host URL path.

s3.url("foo", host: "https://example.com/my-bucket/")
  • Using aws-sdk-s3 older than 1.14 with Shrine::Storage::S3 when uploading files with unknown size is now deprecated and won’t be supported in Shrine 3.

Also, in this case Shrine::Storage::S3 will now first copy the whole file onto disk before uploading it (previously only a chunk of the input file was copied to disk at a time).

If you’re uploading files of unknown size (ones where #size is not defined or returns nil), you should upgrade to aws-sdk-s3 1.14 or higher.