Cloudinary storage for Shrine
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Failed to load latest commit information.


Provides Cloudinary storage for Shrine.

Cloudinary provides storage and advanced processing for images and videos, both on-demand and on upload, automatic and intelligent responsive breakpoints, and an HTML widget for direct uploads.


gem "shrine-cloudinary"


You'll typically want to upload photos directly to Cloudinary, so your setup might look like this:

require "cloudinary"
require "shrine/storage/cloudinary"

  cloud_name: "...",
  api_key:    "...",
  api_secret: "...",

Shrine.storages = {
  cache: "cache"), # for direct uploads
  store: "store"),

Direct uploads

Cloudinary supports uploading files directly to their service, freeing your application from accepting file uploads. There are three ways in which you can do direct uploads:

The first one is the simplest, you can see the demo app with complete implementation using shrine-cloudinary. Unsigned uploads don't require communicating with the server, you just need to set up an "upload preset".

If you would prefer that the server controlls who is allowed to upload, shrine-cloudinary also supports generating presigns, which works with the direct_upload plugin in the same way that S3 does. When rendering on the server side, you can generate a presign inline:

<input name="file" type="file"
   class="cloudinary-fileupload" data-cloudinary-field="image_id"
   data-form-data="<%= Shrine.storages[:cache].presign.fields.to_json %>">

Alternatively you can add an endpoint to your app which can generate presigns on request, which is suitable for apps where templates are rendered on the client-side (see direct_upload documentation):

Shrine.plugin :direct_upload, presign: true
Rails.application.routes.draw do
  mount ImageUploader::UploadEndpoint => "/attachments/images"


If you're using storage as cache where files are accessible over internet, moving the cached file to Cloudinary storage will not require another upload. Instead only the file URL will be passed to Cloudinary, then Cloudinary will internally download it and store the file.

Images, Videos or Raw

The storage defaults the resource type to "image", but you can change that by passing the :resource_type option: "video") # "image", "video" or "raw"


You can choose to store your files in a subdirectory with the :prefix option: "uploads")

Controlling access

You can control access to uploaded files with the :type option: "private") # upload, private or authenticated

Upload options

If you want some Cloudinary options to be applied to all uploads, you can specify :upload_options: {backup: true})

You can also apply upload options dynamically per upload using the upload_options plugin, which is especially useful for doing incoming and eager transformations:

class MyUploader < Shrine
  plugin :upload_options, store: ->(io, context) do
      format: "png",
      eager: [
        {width: 500, height: 500, crop: :scale},
        {width: 300, height: 300, crop: :crop, gravity: :south},

Finally, you can pass upload options when using the uploader directly:

uploader.upload(file, upload_options: {format: "png"})


You can pass transformation options to the URLs:

user.avatar_url(width: 100, height: 100, crop: :fit) # :crop is mandatory with :width or :height
#=> ",h_100,c_fit/nature.jpg"

See Rails image manipulation for all URL options you can pass in.


If you decide to do incoming transformations (processing on upload), shrine-cloudinary will automatically update the extension, size, MIME type, width and height metadata for the uploaded file.

You can choose to save the whole Cloudinary response to metadata by setting :store_data to true: true, **cloudinary_options)
user = User.create(avatar: image_file)
user.avatar.metadata["cloudinary"] #=>
# {
#   "public_id" => "foo",
#   "version" => 1450294102,
#   "signature" => "379ab45c743951abaea38d6a18ee631af599763f",
#   "width" => 100,
#   "height" => 67,
#   "format" => "jpg",
#   "resource_type" => "image",
#   "created_at" => "2015-12-16T19:28:22Z",
#   "tags" => [],
#   "bytes" => 6147,
#   "type" => "upload",
#   "etag" => "54b5d33d07b1dc4084d7694825371cd7",
#   "url" => "\n94102/foo.jpg",
#   "secure_url" => "",
#   "original_filename" => "image"
# }

Responsive breakpoints

Cloudinary has a feature for automagically generating responsive breakpoints for images. In Shrine you can leverage this via :upload_options and :store_data:
  upload_options: {responsive_breakpoints: {...}},
  store_data: true,

Now each upload will generate responsive breakpoints, and the result will be saved in the uploaded file's metadata hash under "cloudinary".

user.avatar.metadata["cloudinary"]["responsive_breakpoints"] #=>
# [{
#   "breakpoints": {
#     {
#       "width": 1000,
#       "height": 667,
#       "bytes": 79821,
#       "url": ",w_1000/v1453637947/dog.jpg",
#       "secure_url": ",w_1000/v1453637947/dog.jpg"
#     },
#     ...
#   }
# }]

If the :responsive_breakpoints value needs to be dynamic, you can use the upload_options plugin:

Shrine.plugin :upload_options, store: -> (io, context) do
  {responsive_breakpoints: {...}}

Large files

If you're uploading large files with Cloudinary (like videos), you can take advantage of Cloudinary's special "chunked" upload API, by passing the filesize threshold after which the special API will be used:

# Upload files larger than 100 MB using the "chunked" upload API 100*1024*1024)

The default chunk size is 20 MB, but you can change that by passing :chunk_size to :upload_options:
  large: 100*1024*1024                      # 100 MB
  upload_options: {chunk_size: 5*1024*1204} # 5 MB


Sometimes you may want to apply actions to already uploaded files, e.g. regenerate tranformations. This storage provides the #update method which delegates to Cloudinary's explicit API:

cloudinary =
# ...
cloudinary.update("image.jpg", eager: {...})

Clearing storage

You can delete all files from the Cloudinary storage in the same way as you do with other storages:

cloudinary =
# ...


Firstly you need to create an .env file with Cloudinary credentials:

# .env

Afterwards you can run the tests:

$ bundle exec rake test


This gem has been inspired by Cloudinary's CarrierWave integration.