Shrine 3.0 Released
I’ve just released version 3.0 of Shrine, a gem for handling file attachments in Ruby applications. It’s been months of hard work, but I feel it’s finally ready.
Redesigned website
The old Jekyll website has been rewritten to use Docusaurus.
Docusaurus gives us nice features such as sidebars with autogenerated TOC and related documents, which greatly improve navigation experience.
We also now have a snippet switcher, which makes it easier to show code for different libraries.
Last but not least, we now have a documentation search bar powered by Algolia DocSearch.
Major features
I’ve talked about the major changes in more detail Upcoming Features in Shrine 3.0, but I’ll give a brief overview here.
Attacher redesign
The Shrine::Attacher
class has been decoupled from the Active
Record pattern. It now supports handling attachments for immutable structs
(which are commonly used in Hanami, ROM, and dry-rb):
class Photo < Hanami::Entity # immutable struct
include ImageUploader::Attachment(:image)
end
photo = photo_repository.find(photo_id)
photo.image #=> #<Shrine::UploadedFile>
attacher = photo.image_attacher
attacher.attach(file) # attach new file
photo_repository.update(photo_id, { image_data: attacher.column_data })
It can also be used standalone:
attacher = ImageUploader::Attacher.new
attacher.attach(file)
attacher.file #=> #<Shrine::UploadedFile>
attacher.url #=> "https://my-bucket.s3.amazonaws.com/path/to/image.jpg"
Versions rewrite
The versions
plugin is used for storing processed files alongside the main
file. Its implementation had many limitations, such as being coupled to the
attachment flow, mixing processed files and original file together, not being
able to specify different storage for processed files etc.
The new derivatives plugin is a rewrite of versions
, offering an
explicit interface and the much needed flexibility.
Shrine.plugin :derivatives
class ImageUploader < Shrine
Attacher.derivatives_processor do |original|
magick = ImageProcessing::MiniMagick.source(original)
{ large: magick.resize_to_limit!(800, 800),
medium: magick.resize_to_limit!(500, 500),
small: magick.resize_to_limit!(300, 300), }
end
end
Processing is now triggered explicitly:
photo = Photo.new(image: file)
photo.image_derivatives! # calls derivatives processor
photo.save
And processed data is saved separately from the original file:
photo.image #=> #<Shrine::UploadedFile @id="30733d04faceec5b.jpg" ...>
photo.image_derivatives #=>
# { large: #<Shrine::UploadedFile @id="86500abe387b20b1.jpg" ...>,
# medium: #<Shrine::UploadedFile @id="9e46ffbcca548290.jpg" ...>,
# small: #<Shrine::UploadedFile @id="f80fb04c3627c5a5.jpg" ...>, }
Mirroring
The mirroring plugin has been added, which allows replicating uploads and deletes to additional storage services. It’s inspired by Active Storage and its mirror service.
Shrine.storages = {
cache: Shrine::Storage::S3.new(prefix: "cache", **s3_options),
store: Shrine::Storage::S3.new(**s3_options),
gcs: Shrine::Storage::GoogleCloudStorage.new(**gcs_options),
}
Shrine.plugin :mirroring, mirror: { store: :gcs }
photo = Photo.create(image: file) # uploads main file to S3 and GCS
photo.image_derivatives! # uploads processed files to S3 and GCS
photo.destroy # deletes files from S3 and GCS
You can also separate the mirroring operations into background jobs, so that they don’t slow down the attachment flow.
Changes
For the full list of changes, see the release notes. If you’re currently on Shrine 2.x, there is a detailed guide for upgrading to Shrine 3.x.
Plugins
The following plugins have been added :
The following plugins have been deprecated :
versions
processing
recache
delete_raw
module_include
The following plugins have been removed :
logging
moving
copy
backup
hooks
parallelize
parsed_json
delete_promoted
multi_delete
direct_upload
background_helpers
migration_helpers
Gems
All official shrine-*
gems have been updated to work with Shrine 3.0:
- shrine-cloudinary
- shrine-flickr
- shrine-fog
- shrine-gridfs
- shrine-imgix
- shrine-mongoid
- shrine-sql
- shrine-transloadit
- shrine-tus
- shrine-uploadcare
- shrine-url
ROM & Hanami integration
As a result of the attacher redesign, Shrine 3.0 should now integrate better with ROM and Hanami. I’m still wrapping up the shrine-rom gem, it should hopefully get released in the next couple of days.
Conclusion
This has been the biggest Shrine release so far . Shrine has been on 2.x for the past three years, and during that time it became obvious that some features weren’t well designed.
Shrine’s plugin architecture helped us a lot in addressing these, as it kept features largely decoupled from one another. This made it easier to identify issues and make changes, as we could work on one feature without affecting others.
Let me know if you have any feedback. Feel free to post on our Discourse forum if you have any troubles upgrading.