File Upload

There are a few file upload gems out there but out of all of them we use Shrine because of it's flexibility and easy-to-extend nature.

Table of contents:

  1. General
  2. Setup
  3. Plugins
  4. Migrating from other uploaders


Shrine is a general purpose file uploader gem. As it has no direct dependency it can be used in both Rails and non-Rails projects. Shrine features a rich plugin system which makes it incredibly easy to change it's behavior to suit your needs. All this power is packaged in an easy-to-use form factor.

It is the youngest of all the popular file uploaders, but maintains an issue count of 0 and has fixed all the issues that the other gems have.

If you wish to read more about Shrine's design you can do so here.

Additionally there exists a demo application. It's not recommended to reference it as it's fairly simplistic and hides many configuration options.


To use shrine in a Rails project you need to do the following:

gem 'shrine'

# Only add this gem if you are going to use Amazon S3 as storage
gem 'aws-sdk', '~> 2.1'

# Only add these gems if you are going to handle image uploads
gem 'mini_magick'
gem 'image_processing'
gem 'fastimage'
# config/initializers/shrine.rb

require 'shrine'
require 'shrine/storage/s3'
require 'shrine/storage/file_system'

# Load application secrets
secrets = Rails.application.secrets

# The following code expects a secrets structure similar to the following
# and uses some Ruby 2.3 features
# development:
#   aws:
#     s3:
#       access_key_id: 'ashkjdsahjas...'
#       secret_access_key: 'ashkjdsahjas...'
#       region: 'ashkjdsahjas...'
#       bucket: 'ashkjdsahjas...'

# Load S3 credentials from secrets
s3_options = {
  access_key_id: secrets.dig(:aws, 's3', 'access_key_id'),
  secret_access_key: secrets.dig(:aws, 's3', 'secret_access_key'),
  region: secrets.dig(:aws, 's3', 'region'),
  bucket: secrets.dig(:aws, 's3', 'bucket')

# Load storage options
storages = {
  cache: nil,
  store: nil

# Set storage options to S3 if S3 credentials have been provided, else use the
# filesystem
storages.keys.each do |store|
  storages[store] = if secrets.dig(:aws, :s3)
             store, **s3_options)
                        prefix: "uploads/#{store}"

# Assign storage options
Shrine.storages = storages

# Load ORM integration
Shrine.plugin :activerecord
# Shrine.plugin :sequel # if you are using Sequel
require 'image_processing/mini_magick'
# app/uploaders/avatar_uploader.rb

class AvatarUploader < Shrine

Shrine's uploaders are mounted on a model using the include keyword. You can specify to which attribute the uploader will get mounted by using the square brackets method on the uploader class.

class User < ActiveRecord::Base
  # The following line will mount an instance of AvatarUploader to the user's
  # avatar attribute
  include AvatarUploader[:avatar]

Shrine assumes that it should use a column bearing the name of the attribute it was mounted on suffixed with _data. E.g. if you mount an uploader on the avatar attribute of the User model. Shrine will store information about the uploaded file to the avatar_data column of the users table. The column's type should either be text, json or jsonb.

rails g migration add_avatar_data_to_users avatar_data:jsonb
= simple_form_for @user do |f|
      = f.input :avatar, as: :hidden, input_html: { value: @user.avatar_data }
      = f.input :avatar, as: :file

If you use simple_form then add the following file to your app/inputs folder

# app/inputs/shrine_file_input.rb

class ShrineFileInput < SimpleForm::Inputs::Base
  def input(wrapper_options)
    merged_input_options = merge_wrapper_options(
      input_html_options, wrapper_options


  def raw_input_html(options)

  def data_attribute

  def hidden_field
      value: object.send(data_attribute).to_json

  def file_field

Then you can use it in your views as follows:

= simple_form_for @user do |f|
      = f.input :avatar, as: :shrine_file


Shrine features quite a few useful plugins out-of-the-box.

The versions plugin allows you to create different versions of an uploaded image. E.g. a small, medium and large version. Read more about it here.

Here is an example of how to use it:

class ImageUploader < Shrine
  include ImageProcessing::MiniMagick
  plugin :versions, names: [:original, :large, :medium, :small]

  def process(io, context)
    return super(io, context) if context[:phase] != :store

    original =
    size_1200 = resize_to_limit(original, 1200, 1200)
    size_600 = resize_to_limit(size_1200, 600, 600)
    size_300 = resize_to_limit(size_600, 300, 300)

    { original: original, large: size_1200, medium: size_600, small: size_300 }

This plugin allows you to check dimensions and file type of uploaded images. Check it out here.

The Metadata plugin is used to store information about uploaded images. You can read more about it here.

Shrine supports background image processing and deletion. You can read here how to set it up.

Migrating from other uploaders

Here are a few articles which explain how to migrate from other uploaders to shrine: