{"id":19777980,"url":"https://github.com/shrinerb/shrine-cloudinary","last_synced_at":"2025-04-30T20:30:40.015Z","repository":{"id":46315917,"uuid":"47718673","full_name":"shrinerb/shrine-cloudinary","owner":"shrinerb","description":"Cloudinary storage for Shrine","archived":false,"fork":false,"pushed_at":"2021-10-31T03:44:20.000Z","size":224,"stargazers_count":24,"open_issues_count":3,"forks_count":6,"subscribers_count":2,"default_branch":"master","last_synced_at":"2024-05-22T17:33:21.913Z","etag":null,"topics":["cloudinary","direct-upload","on-the-fly","processing","shrine","storage"],"latest_commit_sha":null,"homepage":"https://cloudinary.com/","language":"Ruby","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/shrinerb.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.txt","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2015-12-09T21:01:23.000Z","updated_at":"2023-08-15T05:40:56.000Z","dependencies_parsed_at":"2022-08-30T03:41:21.231Z","dependency_job_id":null,"html_url":"https://github.com/shrinerb/shrine-cloudinary","commit_stats":null,"previous_names":[],"tags_count":16,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/shrinerb%2Fshrine-cloudinary","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/shrinerb%2Fshrine-cloudinary/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/shrinerb%2Fshrine-cloudinary/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/shrinerb%2Fshrine-cloudinary/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/shrinerb","download_url":"https://codeload.github.com/shrinerb/shrine-cloudinary/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":224177553,"owners_count":17268695,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cloudinary","direct-upload","on-the-fly","processing","shrine","storage"],"created_at":"2024-11-12T05:27:20.096Z","updated_at":"2024-11-12T05:27:20.763Z","avatar_url":"https://github.com/shrinerb.png","language":"Ruby","readme":"# Shrine::Storage::Cloudinary\n\nProvides [Cloudinary] storage for [Shrine].\n\nCloudinary provides storage and advanced processing for images and videos, both\non-demand and on upload, automatic and intelligent responsive breakpoints, and\nan HTML widget for direct uploads.\n\n## Installation\n\n```ruby\ngem \"shrine-cloudinary\", \"~\u003e 1.1\"\n```\n\n## Usage\n\nYou'll typically want to upload photos directly to Cloudinary, so your setup\nmight look like this:\n\n```rb\nrequire \"cloudinary\"\nrequire \"shrine/storage/cloudinary\"\n\nCloudinary.config(\n  cloud_name: \"...\",\n  api_key:    \"...\",\n  api_secret: \"...\",\n)\n\nShrine.storages = {\n  cache: Shrine::Storage::Cloudinary.new(prefix: \"cache\"), # for direct uploads\n  store: Shrine::Storage::Cloudinary.new,\n}\n```\n\n### Direct uploads\n\nThe `Shrine::Storage::Cloudinary` class implements the `#presign` method, so it\nshould work with Shrine's [presign_endpoint] plugin and Uppy's [AwsS3] plugin.\n\nIf that doesn't work, you can always use Shrine's [upload_endpoint] plugin with\nUppy's [XHRUpload] plugin.\n\n### Copying\n\nIf you're using storage as cache where files are accessible over internet,\nmoving the cached file to Cloudinary storage will not require another upload.\nInstead only the file URL will be passed to Cloudinary, then Cloudinary will\ninternally download it and store the file.\n\n### Images, Videos or Raw\n\nThe storage defaults the resource type to \"image\", but you can change that\nby passing the `:resource_type` option:\n\n```rb\nShrine::Storage::Cloudinary.new(resource_type: \"video\") # \"image\", \"video\" or \"raw\"\n```\n\n### Subdirectory\n\nYou can choose to store your files in a subdirectory with the `:prefix` option:\n\n```rb\nShrine::Storage::Cloudinary.new(prefix: \"uploads\")\n```\n\n### Controlling access\n\nYou can [control access] to uploaded files with the `:type` option:\n\n```rb\nShrine::Storage::Cloudinary.new(type: \"private\") # upload, private or authenticated\n```\n\n### Upload options\n\nIf you want some [Cloudinary options] to be applied to all uploads, you can\nspecify `:upload_options`:\n\n```rb\nShrine::Storage::Cloudinary.new(upload_options: { backup: true })\n```\n\nYou can also apply upload options dynamically per upload using the\n`upload_options` plugin, which is especially useful for doing incoming and\neager transformations:\n\n```rb\nclass MyUploader \u003c Shrine\n  plugin :upload_options, store: -\u003e(io, context) do\n    {\n      format: \"png\",\n      eager: [\n        { width: 500, height: 500, crop: :scale },\n        { width: 300, height: 300, crop: :crop, gravity: :south },\n      ]\n    }\n  end\nend\n```\n\nFinally, you can pass upload options when using the uploader directly:\n\n```rb\nuploader.upload(file, upload_options: { format: \"png\" })\n```\n\n### URLs\n\nYou can pass transformation options to the URLs:\n\n```rb\nuser.avatar_url(width: 100, height: 100, crop: :fit) # :crop is mandatory with :width or :height\n#=\u003e \"https://res.cloudinary.com/myapp/image/upload/w_100,h_100,c_fit/nature.jpg\"\n```\n\nSee [Rails image manipulation] for all URL options you can pass in.\n\n### Metadata\n\nIf you decide to do incoming transformations (processing on upload),\nshrine-cloudinary will automatically update the extension, size, MIME type,\nwidth and height metadata for the uploaded file.\n\nYou can choose to save the whole Cloudinary response to metadata by setting\n`:store_data` to true:\n\n```rb\nShrine::Storage::Cloudinary.new(store_data: true, **cloudinary_options)\n```\n```rb\nuser = User.create(avatar: image_file)\nuser.avatar.metadata[\"cloudinary\"] #=\u003e\n# {\n#   \"public_id\" =\u003e \"foo\",\n#   \"version\" =\u003e 1450294102,\n#   \"signature\" =\u003e \"379ab45c743951abaea38d6a18ee631af599763f\",\n#   \"width\" =\u003e 100,\n#   \"height\" =\u003e 67,\n#   \"format\" =\u003e \"jpg\",\n#   \"resource_type\" =\u003e \"image\",\n#   \"created_at\" =\u003e \"2015-12-16T19:28:22Z\",\n#   \"tags\" =\u003e [],\n#   \"bytes\" =\u003e 6147,\n#   \"type\" =\u003e \"upload\",\n#   \"etag\" =\u003e \"54b5d33d07b1dc4084d7694825371cd7\",\n#   \"url\" =\u003e \"http://res.cloudinary.com/dkjm0biaa/image/upload/v14502\\n94102/foo.jpg\",\n#   \"secure_url\" =\u003e \"https://res.cloudinary.com/dkjm0biaa/image/upload/v1450294102/foo.jpg\",\n#   \"original_filename\" =\u003e \"image\"\n# }\n```\n\n## Responsive breakpoints\n\nCloudinary has a feature for automagically generating [responsive breakpoints]\nfor images. In Shrine you can leverage this via `:upload_options` and\n`:store_data`:\n\n```rb\nShrine::Storage::Cloudinary.new(\n  upload_options: { responsive_breakpoints: {...} },\n  store_data: true,\n)\n```\n\nNow each upload will generate responsive breakpoints, and the result will be\nsaved in the uploaded file's metadata hash under \"cloudinary\".\n\n```rb\nuser.avatar.metadata[\"cloudinary\"][\"responsive_breakpoints\"] #=\u003e\n# [{\n#   \"breakpoints\": {\n#     {\n#       \"width\": 1000,\n#       \"height\": 667,\n#       \"bytes\": 79821,\n#       \"url\": \"http://res.cloudinary.com/demo/image/upload/c_scale,w_1000/v1453637947/dog.jpg\",\n#       \"secure_url\": \"https://res.cloudinary.com/demo/image/upload/c_scale,w_1000/v1453637947/dog.jpg\"\n#     },\n#     ...\n#   }\n# }]\n```\n\nIf the `:responsive_breakpoints` value needs to be dynamic, you can use the\n`upload_options` plugin:\n\n```rb\nShrine.plugin :upload_options, store: -\u003e (io, context) do\n  { responsive_breakpoints: {...} }\nend\n```\n\n### Large files\n\nIf you're uploading large files with Cloudinary (like videos), you can take\nadvantage of Cloudinary's special \"chunked\" upload API, by passing the filesize\nthreshold after which the special API will be used:\n\n```rb\n# Upload files larger than 100 MB using the \"chunked\" upload API\nShrine::Storage::Cloudinary.new(large: 100*1024*1024)\n```\n\nThe default chunk size is 20 MB, but you can change that by passing\n`:chunk_size` to `:upload_options`:\n\n```rb\nShrine::Storage::Cloudinary.new(\n  large: 100*1024*1024                        # 100 MB\n  upload_options: { chunk_size: 5*1024*1204 } # 5 MB\n)\n```\n\n### Updating\n\nSometimes you may want to apply actions to already uploaded files, e.g.\nregenerate tranformations. This storage provides the `#update` method which\ndelegates to Cloudinary's [explicit API]:\n\n```rb\ncloudinary = Shrine::Storage::Cloudinary.new\n# ...\ncloudinary.update(\"image.jpg\", eager: {...})\n```\n\n### Clearing storage\n\nYou can delete all files from the Cloudinary storage in the same way as you do\nwith other storages:\n\n```rb\ncloudinary = Shrine::Storage::Cloudinary.new\n# ...\ncloudinary.clear!\n```\n\n## Contributing\n\nFirstly you need to create an `.env` file with Cloudinary credentials:\n\n```sh\n# .env\nCLOUDINARY_CLOUD_NAME=\"...\"\nCLOUDINARY_API_KEY=\"...\"\nCLOUDINARY_API_SECRET=\"...\"\n```\n\nAfterwards you can run the tests:\n\n```sh\n$ bundle exec rake test\n```\n\n## Inspiration\n\nThis gem has been inspired by Cloudinary's [CarrierWave integration].\n\n## License\n\n[MIT](http://opensource.org/licenses/MIT)\n\n[Cloudinary]: http://cloudinary.com/\n[Shrine]: https://github.com/shrinerb/shrine\n[CarrierWave integration]: https://github.com/cloudinary/cloudinary_gem\n[Cloudinary options]: http://cloudinary.com/documentation/image_upload_api_reference#upload\n[Rails image manipulation]: http://cloudinary.com/documentation/rails_image_manipulation\n[responsive breakpoints]: http://cloudinary.com/blog/introducing_intelligent_responsive_image_breakpoints_solutions\n[explicit API]: http://cloudinary.com/documentation/image_upload_api_reference#explicit\n[control access]: http://cloudinary.com/documentation/upload_images#control_access_to_images\n[presign_endpoint]: https://github.com/shrinerb/shrine/blob/master/doc/plugins/presign_endpoint.md#readme\n[upload_endpoint]: https://github.com/shrinerb/shrine/blob/master/doc/plugins/upload_endpoint.md#readme\n[AwsS3]: https://uppy.io/docs/aws-s3/\n[XHRUpload]: https://uppy.io/docs/xhr-upload/\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fshrinerb%2Fshrine-cloudinary","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fshrinerb%2Fshrine-cloudinary","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fshrinerb%2Fshrine-cloudinary/lists"}