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

title: Shrine 2.6.0

New plugins

  • Added signature plugin which allows you to calculate a SHA{1,256,384,512}/MD5/CRC32 hash of a file, in raw, hex or base64 encoding.

Shrine.plugin :signature

Shrine.calculate_signature(io, :md5)
#=> "8c7dd922ad47494fc02c388e12c00eac"

Shrine.calculate_signature(io, :md5, format: :base64)
#=> "jH3ZIq1HSU/ALDiOEsAOrA==\n"

You can then easily create a new metadata field with the calculated hash:

Shrine.plugin :signature
Shrine.plugin :add_metadata

MyUploader.add_metadata :md5 do |io, context|
  calculate_signature(io, :md5)
  • Added metadata_attibutes plugin which allows you to sync attachment metadata to additional record attributes.

Shrine.plugin :metadata_attributes

# Syncs `size` metadata to `#<attachment>_size` record attribute, and
# `mime_type` metadata to `#<attachment>_type` record attribute.
Shrine::Attacher.metadata_attributes :size => :size, :mime_type => :type

# ...

user.avatar = image
user.avatar.metadata["size"]      #=> 95724
user.avatar_size                  #=> 95724
user.avatar.metadata["mime_type"] #=> "image/jpeg"
user.avatar_type                  #=> "image/jpeg"

user.avatar = nil
user.avatar_size #=> nil
user.avatar_type #=> nil
  • Added refresh_metadata plugin (extracted from the restore_cached_data plugin) which allows you to re-extract metadata from an uploaded file.

Shrine.plugin :refresh_metadata

# ...

uploaded_file.metadata # re-extracted metadata

New features

  • Added Shrine.determine_mime_type and Shrine.mime_type_analyzers methods to determine_mime_type plugin for extracting MIME type from a file.

Shrine.plugin :determine_mime_type

Shrine.determine_mime_type(io) # calls the defined analyzer
#=> "image/jpeg"

Shrine.mime_type_analyzers[:file].call(io) # calls a built-in analyzer
#=> "image/jpeg"
  • Added Shrine.extract_dimensions and Shrine.dimensions_analyzers methods to store_dimensions plugin for extracting dimensions from a file.

Shrine.plugin :store_dimensions

Shrine.extract_dimensions(io) # calls the defined analyzer
#=> [300, 400]

Shrine.dimensions_analyzers[:fastimage].call(io) # calls a built-in analyzer
#=> [300, 400]
  • Added Shrine.data_uri method to data_uri plugin for converting a data URI into an IO object.

Shrine.plugin :data_uri

io = Shrine.data_uri("data:image/png;base64,9kfg07a80ihtiort87t85")
io.content_type #=> "image/png"
io.size         #=> 482
  • Added Shrine.rack_file method to rack_file plugin for converting the Rack uploaded file hash into an IO object.

Shrine.plugin :rack_file

file_hash #=>
# {
#   :name => "file",
#   :filename => "cats.png",
#   :type => "image/png",
#   :tempfile => #<Tempfile:/var/folders/3n/3asd/-Tmp-/RackMultipart201-1476-nfw2-0>,
#   :head => "Content-Disposition: form-data; ...",
# }

io = Shrine.rack_file(file_hash)
io.original_filename #=> "cats.png"
io.content_type      #=> "image/png"
io.size              #=> 58342

Performance improvements

  • Improved performance of parsing data URIs up to 10x by switching from regex matching to StringScanner, and the intermediary base64-encoded content string is now deallocated after it's decoded.

  • UploadedFile#base64 now deallocates the intermediary binary content string after converting it to base64 format in data_uri plugin.

  • The default multipart copy threshold for Shrine::Storage::S3 has been bumped from 15MB to 100MB, which is about the size where parallelized multipart copy starts being faster.

  • Uploading files from FileSystem storage to S3 storage will now utilize aws-sdk's parallelized multipart upload on files with 15MB or above, which is the scenario when your temporary storage is FileSystem and permanent storage is S3.

  • Shrine::Storage::S3#download now uses only one file descriptor.

  • The logging plugin doesn't require the benchmark standard library anymore, which reduces the memory footprint.

Other improvements

  • Fixed wrong implementation of FileSystem#clear!(older_than: expiration_date), where in common scenarios it wouldn't delete old files, or it would incorrectly delete files which still didn't pass the expiration date.

  • The delete_raw plugin now deletes any uploaded IO objects that respond to #path, not just Tempfile objects (this includes File, ActionDispatch::Http::UploadedFile, and Shrine::Plugins::RackFile::UploadedFile objects).

  • The rack_file plugin now works with Grape.

  • The data_uri plugin now accepts URI-encoded raw data URIs.

  • The data_uri plugin now accepts data URIs with additional media type params.

  • Shrine::Storage::S3 now accepts separate multipart thresholds for uploading and for copying.

  • Shrine::Storage::S3#object is now public, which returns an Aws::S3::Object representing the file.

s3.object("image.jpg") #=> #<Aws::S3::Object bucket_name="your-bucket" key="image.jpg">
  • Added Shrine::Storage::S3#client method for quicker access to the Aws::S3::Client instance.

  • The "S3" component of the aws-sdk gem is now eagerly loaded in lib/shrine/storage/s3.rb, to remove possibility of autoloading causing errors in multi-threaded systems.

  • Shrine::Storage::FileSystem#path is now public, which returns a Pathname to the file.

filesystem.path("image.jpg") #=> #<Pathname:public/image.jpg>
  • Shrine now checks whether Shrine#generate_location happened to return nil, and raises Shrine::Error.

  • Attacher#finalize can now be called even when the attachment hasn’t changed.

  • Added Attacher#changed? alias to Attacher#attached?.

  • The logic for rejecting attachments that are already the current attachment has been moved from Attacher#assign to Attacher#set.

  • The remove_invalid plugin will now only remove new invalid attachments.

  • The tempfile standard library is now correctly required in lib/shrine.rb.

  • Improved default validation error messages in validation_helpers plugin.

  • Blacklisted MIME types and extensions are now excluded from the default error message for security reasons.

  • The add_metadata plugin now also accepts hashes with symbol keys.

  • The loaded plugin module is now returned when calling Shrine.plugin.

  • Improved visibility of Shrine deprecation warnings.

Backwards compatibility

  • Passing regexes to validate_(mime_type|extension)_(inclusion|exclusion) has been deprecated due to lack of usefulness and for security reasons, from now on you should always pass plain strings.

# deprecated
validate_mime_type_inclusion [/image\//]
validate_extension_inclusion [/jpe?g/]

# use strings instead
validate_mime_type_inclusion %w[image/jpeg image/png image/gif ...]
validate_extension_inclusion %w[jpg jpeg png gif ...]
  • Previously the validate_(max|min)_(width|height) validations would ignore width or height being nil, but this is now deprecated and in Shrine 3 this will return an error. You should make sure that the file is of the right type before validating dimensions.

if validate_mime_type_inclusion %w[image/jpeg image/png image/gif]
  validate_max_width 1000
  validate_max_height 1000
  • Passing a Rack uploaded file hash to Shrine#upload and Shrine#store is now deprecated in rack_file plugin, use Shrine.rack_file to first convert the Rack hash into an IO object.

  • Deprecated passing :multipart_threshold option as an integer in Shrine::Storage::S3, use a hash with :upload and :copy keys.

  • Deprecated Shrine::Storage::S3#s3 in favour of Shrine::Storage::S3#client.

  • The Shrine::Plugins::DataUri::DataFile isn't a subclass of StringIO anymore, instead it uses composition to delegate only a subset of IO methods to the underlying StringIO object. This shouldn't cause any backwards compatibility unless the user was relying on it to be a subclass of StringIO.