Top Related Projects
The next open source file uploader for web browsers :dog:
Classier solution for file uploads for Rails, Sinatra and other Ruby web frameworks
Ruby file uploads, take 3
Easy file attachment management for ActiveRecord
mini replacement for RMagick
Quick Overview
Shrine is a flexible file attachment toolkit for Ruby applications. It provides a complete solution for handling file uploads, storage, and processing, with support for various storage services and image processing libraries. Shrine is designed to be modular and customizable, allowing developers to tailor it to their specific needs.
Pros
- Highly flexible and customizable, with a plugin system for extending functionality
- Supports multiple storage services (local, S3, Google Cloud Storage, etc.)
- Provides built-in file validation and processing capabilities
- Excellent documentation and active community support
Cons
- Steeper learning curve compared to simpler file upload solutions
- May be overkill for simple file upload requirements
- Requires additional setup and configuration for advanced features
- Performance can be impacted when handling large numbers of uploads simultaneously
Code Examples
- Basic file upload and retrieval:
class PhotoUploader < Shrine
# plugins and uploading logic
end
class Photo < ApplicationRecord
include PhotoUploader::Attachment(:image)
end
# Upload a file
photo = Photo.new(image: File.open("path/to/image.jpg", "rb"))
photo.save
# Retrieve the file URL
photo.image_url #=> "https://my-bucket.s3.amazonaws.com/path/to/image.jpg"
- Image processing with derivatives:
require "image_processing/mini_magick"
class ImageUploader < Shrine
plugin :derivatives
Attacher.derivatives do |original|
magick = ImageProcessing::MiniMagick.source(original)
{
small: magick.resize_to_limit!(300, 300),
medium: magick.resize_to_limit!(500, 500),
large: magick.resize_to_limit!(800, 800),
}
end
end
photo.image_derivatives! # generate derivatives
photo.image_url(:small) #=> "https://my-bucket.s3.amazonaws.com/path/to/small.jpg"
- Direct uploads to S3:
class PhotoUploader < Shrine
plugin :presign_endpoint, presign_options: -> (request) {
{ content_disposition: ContentDisposition.inline(request.params["filename"]) }
}
end
# In your routes.rb
Rails.application.routes.draw do
mount PhotoUploader.presign_endpoint(:cache) => "/s3/params"
end
Getting Started
- Add Shrine to your Gemfile:
gem "shrine", "~> 3.0"
- Create an initializer (e.g.,
config/initializers/shrine.rb
):
require "shrine"
require "shrine/storage/file_system"
Shrine.plugin :activerecord
Shrine.plugin :cached_attachment_data
Shrine.plugin :restore_cached_data
Shrine.storages = {
cache: Shrine::Storage::FileSystem.new("public", prefix: "uploads/cache"),
store: Shrine::Storage::FileSystem.new("public", prefix: "uploads"),
}
- Generate an uploader and include it in your model:
class ImageUploader < Shrine
# plugins and uploading logic
end
class Photo < ApplicationRecord
include ImageUploader::Attachment(:image)
end
Competitor Comparisons
The next open source file uploader for web browsers :dog:
Pros of Uppy
- Cross-platform support: Works with various JavaScript frameworks and can be used in both browser and Node.js environments
- Rich UI components: Provides pre-built UI elements for a polished file upload experience
- Extensive plugin ecosystem: Offers a wide range of plugins for additional functionality
Cons of Uppy
- JavaScript-only: Limited to JavaScript environments, unlike Shrine which is Ruby-based
- Potentially heavier: May have a larger footprint due to its comprehensive feature set
- Learning curve: More complex API compared to Shrine's simpler approach
Code Comparison
Uppy (JavaScript):
const uppy = new Uppy()
.use(Dashboard, { trigger: '#select-files' })
.use(Tus, { endpoint: '/uploads' })
.on('complete', (result) => {
console.log('Upload complete! We've uploaded these files:', result.successful)
})
Shrine (Ruby):
class ImageUploader < Shrine
plugin :derivation_endpoint, prefix: "derivations/image"
derivation :thumbnail do |file, width, height|
file.resize_to_limit!(width.to_i, height.to_i)
end
end
This comparison highlights the different approaches and languages used by Uppy and Shrine, showcasing Uppy's JavaScript-based configuration and Shrine's Ruby-based setup for file uploads and image processing.
Classier solution for file uploads for Rails, Sinatra and other Ruby web frameworks
Pros of CarrierWave
- Simpler setup and configuration for basic use cases
- Built-in image processing capabilities using RMagick or MiniMagick
- Extensive documentation and large community support
Cons of CarrierWave
- Less flexible and modular architecture compared to Shrine
- Performance can be slower, especially for larger file uploads
- Limited support for direct uploads and background processing
Code Comparison
CarrierWave:
class ImageUploader < CarrierWave::Uploader::Base
include CarrierWave::MiniMagick
version :thumb do
process resize_to_fit: [50, 50]
end
end
Shrine:
class ImageUploader < Shrine
plugin :derivatives
Attacher.derivatives do |original|
magick = ImageProcessing::MiniMagick.source(original)
{ thumb: magick.resize_to_limit!(50, 50) }
end
end
Both CarrierWave and Shrine are popular file upload solutions for Ruby applications. CarrierWave offers a simpler setup and built-in image processing, making it easier for beginners. However, Shrine provides a more flexible and modular architecture, better performance, and advanced features like direct uploads and background processing. The code comparison shows how both libraries handle image processing, with Shrine offering a more streamlined approach using plugins and derivatives.
Ruby file uploads, take 3
Pros of Refile
- Simpler and more lightweight, making it easier to set up and use for basic file upload needs
- Built-in image processing capabilities without additional dependencies
- Seamless integration with ActiveRecord for easy attachment handling
Cons of Refile
- Less flexible and customizable compared to Shrine
- Limited support for advanced features like background processing and direct uploads
- No longer actively maintained, which may lead to compatibility issues with newer Ruby versions
Code Comparison
Refile:
class User < ApplicationRecord
attachment :profile_image
end
<%= form.attachment_field :profile_image %>
Shrine:
class User < ApplicationRecord
include ImageUploader::Attachment(:profile_image)
end
<%= form.file_field :profile_image, accept: "image/*" %>
Both Shrine and Refile are file attachment libraries for Ruby applications, but they differ in their approach and features. Shrine offers more flexibility and advanced capabilities, making it suitable for complex file handling requirements. It supports various storage backends, plugins, and direct uploads.
Refile, on the other hand, provides a simpler solution with built-in image processing, making it easier to get started with basic file uploads. However, its development has slowed down, which may be a concern for long-term project maintenance.
When choosing between the two, consider your project's specific needs, desired level of customization, and long-term maintenance requirements.
Easy file attachment management for ActiveRecord
Pros of Paperclip
- Simpler setup and configuration for basic use cases
- Tighter integration with ActiveRecord models
- Well-established and widely used in Rails community
Cons of Paperclip
- Limited flexibility for complex file processing workflows
- Lack of support for direct uploads and background processing
- No longer actively maintained (deprecated in favor of Active Storage)
Code Comparison
Paperclip:
class User < ActiveRecord::Base
has_attached_file :avatar, styles: { medium: "300x300>", thumb: "100x100>" }
validates_attachment_content_type :avatar, content_type: /\Aimage\/.*\z/
end
Shrine:
class User < ActiveRecord::Base
include ImageUploader::Attachment(:avatar)
end
class ImageUploader < Shrine
plugin :derivatives
plugin :validation_helpers
Attacher.derivatives do |original|
magick = ImageProcessing::MiniMagick.source(original)
{ medium: magick.resize_to_limit!(300, 300),
thumb: magick.resize_to_limit!(100, 100) }
end
Attacher.validate do
validate_mime_type %w[image/jpeg image/png image/webp]
end
end
Shrine offers more flexibility and advanced features, while Paperclip provides a simpler setup for basic use cases. Shrine's code is more verbose but allows for greater customization and separation of concerns.
mini replacement for RMagick
Pros of MiniMagick
- Lightweight and focused specifically on image processing
- Simple API for common image manipulation tasks
- Extensive support for various image formats
Cons of MiniMagick
- Limited to image processing, not a full-featured file upload solution
- Requires ImageMagick to be installed on the system
- Less flexibility for handling non-image file types
Code Comparison
MiniMagick:
image = MiniMagick::Image.open("input.jpg")
image.resize "300x300"
image.format "png"
image.write "output.png"
Shrine:
uploaded_file = Shrine.upload(File.open("input.jpg"), :store)
processed = uploaded_file.derivation(:resize).call("300x300")
processed.download.path # => path to resized image
Summary
MiniMagick is a lightweight gem focused on image processing, offering a simple API for common tasks. It requires ImageMagick to be installed and is limited to image manipulation. Shrine, on the other hand, is a more comprehensive file attachment toolkit that handles various file types and provides a flexible plugin system. While MiniMagick excels in straightforward image processing, Shrine offers a more robust solution for file uploads and storage in Ruby applications.
Convert designs to code with AI
Introducing Visual Copilot: A new AI model to turn Figma designs to high quality code using your components.
Try Visual CopilotREADME
Shrine
Shrine is a toolkit for handling file attachments in Ruby applications. Some highlights:
- Modular design â the plugin system allows you to load only the functionality you need
- Memory friendly â streaming uploads and downloads make it work great with large files
- Cloud storage â store files on disk, AWS S3, Google Cloud, Cloudinary and others
- Persistence integrations â works with Sequel, ActiveRecord, ROM, Hanami and Mongoid and others
- Flexible processing â generate thumbnails eagerly or on-the-fly using ImageMagick or libvips
- Metadata validation â validate files based on extracted metadata
- Direct uploads â upload asynchronously to your app or to the cloud using Uppy
- Resumable uploads â make large file uploads resumable on S3 or tus
- Background jobs â built-in support for background processing that supports any backgrounding library
If you're curious how it compares to other file attachment libraries, see the Advantages of Shrine. Otherwise, follow along with the Getting Started guide.
Links
Resource | URL |
---|---|
Website & Documentation | shrinerb.com |
Demo code | Roda / Rails |
Wiki | github.com/shrinerb/shrine/wiki |
Discussion forum | github.com/shrinerb/shrine/discussions |
Alternate Discussion forum | discourse.shrinerb.com |
Setup
Run:
bundle add shrine
Then add config/initializers/shrine.rb
which sets up the storage and loads
ORM integration:
require "shrine"
require "shrine/storage/file_system"
Shrine.storages = {
cache: Shrine::Storage::FileSystem.new("public", prefix: "uploads/cache"), # temporary
store: Shrine::Storage::FileSystem.new("public", prefix: "uploads"), # permanent
}
Shrine.plugin :activerecord # loads Active Record integration
Shrine.plugin :cached_attachment_data # enables retaining cached file across form redisplays
Shrine.plugin :restore_cached_data # extracts metadata for assigned cached files
Next, add the <name>_data
column to the table you want to attach files to. For
an "image" attachment on a photos
table this would be an image_data
column:
$ rails generate migration add_image_data_to_photos image_data:text # or :jsonb
If using jsonb
consider adding a gin index for fast key-value pair searchability within image_data
.
Now create an uploader class (which you can put in app/uploaders
) and
register the attachment on your model:
class ImageUploader < Shrine
# plugins and uploading logic
end
class Photo < ActiveRecord::Base
include ImageUploader::Attachment(:image) # adds an `image` virtual attribute
end
In our views let's now add form fields for our attachment attribute that will allow users to upload files:
<%= form_for @photo do |f| %>
<%= f.hidden_field :image, value: @photo.cached_image_data, id: nil %>
<%= f.file_field :image %>
<%= f.submit %>
<% end %>
When the form is submitted, in your controller you can assign the file from request params to the attachment attribute on the model:
class PhotosController < ApplicationController
def create
Photo.create(photo_params) # attaches the uploaded file
# ...
end
private
def photo_params
params.require(:photo).permit(:image)
end
end
Once a file is uploaded and attached to the record, you can retrieve the file URL and display it on the page:
<%= image_tag @photo.image_url %>
See the Getting Started guide for further documentation.
Inspiration
Shrine was heavily inspired by Refile and Roda. From Refile it borrows the idea of "backends" (here named "storages"), attachment interface, and direct uploads. From Roda it borrows the implementation of an extensible plugin system.
Similar libraries
- Paperclip
- CarrierWave
- Dragonfly
- Refile
- Active Storage
Contributing
Please refer to the contributing page.
Code of Conduct
Everyone interacting in the Shrine projectâs codebases, issue trackers, and mailing lists is expected to follow the Shrine code of conduct.
License
The gem is available as open source under the terms of the MIT License.
Top Related Projects
The next open source file uploader for web browsers :dog:
Classier solution for file uploads for Rails, Sinatra and other Ruby web frameworks
Ruby file uploads, take 3
Easy file attachment management for ActiveRecord
mini replacement for RMagick
Convert designs to code with AI
Introducing Visual Copilot: A new AI model to turn Figma designs to high quality code using your components.
Try Visual Copilot