Skip to main content

Shrine 2.14.0

New features

  • Shrine::Storage::S3 now accepts a :client option for specifying an AWS SDK client object. This allows the user to configure client-side encryption by passing a Aws::S3::Encryption::Client object:

    client =
      kms_key_id: "alias/my-key",
    ) client, bucket: "my-bucket")
  • The metadata blocks in the add_metadata plugin now have previous metadata available to them in context[:metadata] (thanks to @jrochkind).

    add_metadata :foo do |io, context|
      context[:metadata] #=>
      # {
      #   "filename"  => "nature.jpg",
      #   "size"      => 123,
      #   "mime_type" => "image/jpeg"
      # }
    add_metadata :bar do |io, context|
      context[:metadata] #=>
      # {
      #   "filename"  => "nature.jpg",
      #   "size"      => 123,
      #   "mime_type" => "image/jpeg",
      #   "foo"       => "foo"
      # }
  • UploadedFile#to_rack_response from rack_response plugin now accepts :type and :filename options for overriding the values in metadata that would otherwise be used for the Content-Type and Content-Disposition response headers.

    status, headers, body = uploaded_file.to_rack_response(
      type:     "text/csv; charset=utf-8",
      filename: "export.csv",
    headers["Content-Type"]        #=> "text/csv; charset=utf-8"
    headers["Content-Disposition"] #=> "inline; filename=\"export.csv\""
  • Shrine.data_uri from data_uri plugin now accepts a :filename string, which will be returned in Shrine::Plugins::DataUri::DataFile#original_filename.

    io = Shrine.data_uri("data:,content", filename: "foo.txt")
    io.original_filename #=> "foo.txt"
  • UploadedFile#download_url from download_endpoint plugin now accepts a :host option. Previously it was only possible to configure the URL host on the plugin level.

    uploaded_file.download_url(host: "")
  • Attacher#cached? and Attacher#stored? now accept an optional uploaded file parameter, and return whether the given uploaded file is uploaded to the temporary or permanent storage of the attacher (thanks to @jrochkind).

Performance improvements

  • UploadedFile#download doesn't call Storage#download anymore (only Storage#open). This improves performance when the uploaded file is already opened, e.g. when using refresh_metadata plugin and Shrine.with_file during metadata extraction. Instead of performing a new download request, UploadedFile#download will in this case reuse the already opened IO object.

  • Added tempfile plugin that makes it easier to avoid copying the UploadedFile to disk multiple times during promotion. For example, in the following code the uploaded file will be downloaded to disk only once instead of three times.

    Shrine.plugin :tempfile
    class MyUploader < Shrine
      plugin :processing
      plugin :add_metadata
      plugin :refresh_metadata
      process(:store) do |io, context| do
          processor = ImageProcessing::Vips.source(io.tempfile)
          # ... processing ...
      add_metadata :foo do |io, context|
        Shrine.with_file(io) { "..." } unless context[:action] == :store
      add_metadata :bar do |io, context|
        Shrine.with_file(io) { "..." } unless context[:action] == :store
  • UploadedFile#refresh_metadata! from refresh_metadata plugin now detects when the uploaded file is already opened and in that case doesn't re-open the file. This makes code like this faster: do
      uploaded_file.refresh_metadata! # doesn't re-open the file anymore
  • The rack_response plugin now integrates with Rack::Sendfile middleware when Shrine::Storage::FileSystem is used. It does so by making the response body respond to #to_path.

  • #<name>_attacher doesn't look up the attachment class every time it's called with a new model instance anymore, making it slightly faster (thanks to @printercu).

Other improvements

  • The lib/shrine.rb file has been split into lib/shrine.rb, lib/shrine/uploaded_file.rb, lib/shrine/attacher.rb, lib/shrine/attachment.rb, and lib/shrine/plugins.rb (thanks to @printercu).

  • Shrine::Storage::S3 and rack_response plugin now use the content_disposition gem for generating correctly formatted Content-Disposition header values.

  • The S3#download and S3#open methods now work correctly with server-side encryption (as long as the necessary :sse_* parameters are passed in).

  • Fixed FileSystem#clear! not working with symlinks (at least on MRI).

  • Fixed add_metadata plugin overriding previously defined metadata blocks when loaded again.

  • Fixed processing plugin overriding previously defined processing blocks when loaded again.

  • Fixed backgrounding plugin erroring when temorary/permanent storage is declared in and there are no :cache or :store storages defined.

  • Fixed UploadedFile#extension (and thus the tempfile in UploadedFile#download) including URL query parameters in the file extension when Shrine::Storage::Url is used (shrine-url gem) with URLs that have query parameters (thanks to @jrochkind).

  • Fixed backgrounding plugin aborting promotion when cached file metadata was refreshed in the processing block and Active Record JSON column was used.

    • refresh_metadata plugin now avoids mutating the uploaded file data hash
    • backgrounding plugin now continues promotion if cached file metadata has changed
  • The Shrine.data_uri method from the data_uri plugin now picks up media type parameters from the data URI and includes them in Shrine::Plugins::DataUri::DataFile#content_type.

    io = Shrine.data_uri("data:text/plain;charset=utf-8,content")
    io.content_type #=>
    # BEFORE: "text/plain"
    # AFTER:  "text/plain;charset=utf-8"
  • When fetching mime_type metadata value from io.content_type, any media type parameters are now stripped. This means that if the user uploads a text file with a Content-Type of text/plain; charset=utf-8, the mime_type will now correctly be stored as text/plain. This fixes any MIME type validations that might not have been passing due to additional media type parameters.

  • When determine_mime_type plugin is loaded with the :default analyzer, a warning is not printed anymore.

  • When Shrine::Storage::S3 is initialized with bucket: nil, an appropriate error message is now raised.

  • The :content_type MIME type analyzer has been added to the Shrine.mime_type_analyzers hash in determine_mime_type plugin (previously known as :default).


Backwards compatibility

  • Support for MRI 2.1 and MRI 2.2 has been dropped.

  • Shrine::Plugins::Base module has been removed and contained modules have been moved to InstanceMethods and ClassMethods modules inside the corresponding core classes. This should not break anything unless you were referencing those modules directly.

    Shrine::Plugins::Base::InstanceMethods        => Shrine::InstanceMethods
    Shrine::Plugins::Base::ClassMethods           => Shrine::ClassMethods
    Shrine::Plugins::Base::FileMethods            => Shrine::UploadedFile::InstanceMethods
    Shrine::Plugins::Base::FileClassMethods       => Shrine::UploadedFile::ClassMethods
    Shrine::Plugins::Base::AttacherMethods        => Shrine::Attacher::InstanceMethods
    Shrine::Plugins::Base::AttacherClassMethods   => Shrine::Attacher::ClassMethods
    Shrine::Plugins::Base::AttachmentMethods      => Shrine::Attachment::InstanceMethods
    Shrine::Plugins::Base::AttachmentClassMethods => Shrine::Attachment::ClassMethods
  • UploadedFile#download doesn't call Storage#download anymore, it now always calls Storage#open. Since Storage#download is not used anywhere else in Shrine, storages can remove the #download method.

  • Shrine::Storage::S3#download has been deprecated and will be removed in Shrine 3.

  • In Shrine::Storage::S3#upload, #open, and #presign it's now deprecated to pass the Content-Disposition header value with non-ASCII characters. Starting with Shrine 3 these characters won't be escaped anymore. You should now use the content_disposition gem to properly format the Content-Disposition header value.

    # BAD:
    plugin :default_url_options, store: -> (io, **options) do
      { response_content_disposition: "attachment; filename=\"#{io.original_filename}\"" }
    # GOOD:
    plugin :default_url_options, store: -> (io, **options) do
      { response_content_disposition: ContentDisposition.attachment(io.original_filename) }
  • The mime_type metadata value will now strip any additional media type parameters such as charset from io.content_type. If you were relying on this behaviour, you will need to update your code.

  • In determine_mime_type plugin, the :default MIME type analyzer has been renamed to :content_type. The :default alias will stop being supported in Shrine 3.

    plugin :determine_mime_type, analyzer: :default
    # should be changed to
    plugin :determine_mime_type, analyzer: :content_type
  • The UploadedFile private methods that were added by the rack_response plugin have now been moved to an internal class (leaving only #to_rack_response). If you've are currently overriding any of these private methods, you'll need to update your code.

  • The UploadedFile private methods that were added by the download_endpoint plugin have now been moved to an internal class (leaving only #download_url). If you've are currently overriding any of these private methods, you'll need to update your code.