{"id":13411893,"url":"https://github.com/shrinerb/shrine","last_synced_at":"2025-05-13T16:06:16.388Z","repository":{"id":37887160,"uuid":"44935124","full_name":"shrinerb/shrine","owner":"shrinerb","description":"File Attachment toolkit for Ruby applications","archived":false,"fork":false,"pushed_at":"2024-09-09T15:54:23.000Z","size":14191,"stargazers_count":3205,"open_issues_count":22,"forks_count":273,"subscribers_count":38,"default_branch":"master","last_synced_at":"2025-04-17T20:40:47.870Z","etag":null,"topics":["attachment","background-jobs","direct-upload","file-upload","filesystem","metadata","orm","rack","ruby","s3","storage"],"latest_commit_sha":null,"homepage":"https://shrinerb.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":"CHANGELOG.md","contributing":"CONTRIBUTING.md","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,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null},"funding":{"github":"janko","open_collective":"shrine"}},"created_at":"2015-10-25T23:33:32.000Z","updated_at":"2025-04-10T02:36:00.000Z","dependencies_parsed_at":"2023-09-29T08:56:40.436Z","dependency_job_id":"ba1303b4-29ec-4db0-994f-b7b4bdf56a63","html_url":"https://github.com/shrinerb/shrine","commit_stats":{"total_commits":2335,"total_committers":107,"mean_commits":"21.822429906542055","dds":"0.10278372591006424","last_synced_commit":"ef636ceb37e14a2f686bcca69e6637dd651eb831"},"previous_names":["janko-m/shrine"],"tags_count":53,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/shrinerb%2Fshrine","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/shrinerb%2Fshrine/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/shrinerb%2Fshrine/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/shrinerb%2Fshrine/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/shrinerb","download_url":"https://codeload.github.com/shrinerb/shrine/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":250440092,"owners_count":21430950,"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":["attachment","background-jobs","direct-upload","file-upload","filesystem","metadata","orm","rack","ruby","s3","storage"],"created_at":"2024-07-30T20:01:18.148Z","updated_at":"2025-04-23T20:55:18.563Z","avatar_url":"https://github.com/shrinerb.png","language":"Ruby","readme":"# [Shrine]\n\n\u003cimg src=\"https://shrinerb.com/img/logo.png\" width=\"100\" alt=\"Shrine logo: a red paperclip\" align=\"right\" /\u003e\n\nShrine is a toolkit for handling file attachments in Ruby applications. Some highlights:\n\n* **Modular design** – the [plugin system] allows you to load only the functionality you need\n* **Memory friendly** – streaming uploads and [downloads][Retrieving Uploads] make it work great with large files\n* **Cloud storage** – store files on [disk][FileSystem], [AWS S3][S3], [Google Cloud][GCS], [Cloudinary] and others\n* **Persistence integrations** – works with [Sequel], [ActiveRecord], [ROM], [Hanami] and [Mongoid] and others\n* **Flexible processing** – generate thumbnails [eagerly] or [on-the-fly] using [ImageMagick] or [libvips]\n* **Metadata validation** – [validate files][validation] based on [extracted metadata][metadata]\n* **Direct uploads** – upload asynchronously [to your app][simple upload] or [to the cloud][presigned upload] using [Uppy]\n* **Resumable uploads** – make large file uploads [resumable][resumable upload] on [S3][uppy-s3_multipart] or [tus][tus-ruby-server]\n* **Background jobs** – built-in support for [background processing][backgrounding] that supports [any backgrounding library][Backgrounding Libraries]\n\nIf you're curious how it compares to other file attachment libraries, see the\n[Advantages of Shrine]. Otherwise, follow along with the **[Getting Started\nguide]**.\n\n## Links\n\n| Resource                   | URL                                                                                      |\n| :----------------          | :-----------------------------------------------------------------------------           |\n| Website \u0026 Documentation    | [shrinerb.com](https://shrinerb.com)                                                     |\n| Demo code                  | [Roda][roda demo] / [Rails][rails demo]                                                  |\n| Wiki                       | [github.com/shrinerb/shrine/wiki](https://github.com/shrinerb/shrine/wiki)               |\n| Discussion forum           | [github.com/shrinerb/shrine/discussions](https://github.com/shrinerb/shrine/discussions) |\n| Alternate Discussion forum | [discourse.shrinerb.com](https://discourse.shrinerb.com)                                 |\n\n## Setup\n\nRun:\n\n```sh\nbundle add shrine\n```\n\nThen add `config/initializers/shrine.rb` which sets up the storage and loads\nORM integration:\n\n```rb\nrequire \"shrine\"\nrequire \"shrine/storage/file_system\"\n\nShrine.storages = {\n  cache: Shrine::Storage::FileSystem.new(\"public\", prefix: \"uploads/cache\"), # temporary\n  store: Shrine::Storage::FileSystem.new(\"public\", prefix: \"uploads\"),       # permanent\n}\n\nShrine.plugin :activerecord           # loads Active Record integration\nShrine.plugin :cached_attachment_data # enables retaining cached file across form redisplays\nShrine.plugin :restore_cached_data    # extracts metadata for assigned cached files\n```\n\nNext, add the `\u003cname\u003e_data` column to the table you want to attach files to. For\nan \"image\" attachment on a `photos` table this would be an `image_data` column:\n\n```\n$ rails generate migration add_image_data_to_photos image_data:text # or :jsonb\n```\nIf using `jsonb` consider adding a [gin index] for fast key-value pair searchability within `image_data`.\n\nNow create an uploader class (which you can put in `app/uploaders`) and\nregister the attachment on your model:\n\n```rb\nclass ImageUploader \u003c Shrine\n  # plugins and uploading logic\nend\n```\n```rb\nclass Photo \u003c ActiveRecord::Base\n  include ImageUploader::Attachment(:image) # adds an `image` virtual attribute\nend\n```\n\nIn our views let's now add form fields for our attachment attribute that will\nallow users to upload files:\n\n```erb\n\u003c%= form_for @photo do |f| %\u003e\n  \u003c%= f.hidden_field :image, value: @photo.cached_image_data, id: nil %\u003e\n  \u003c%= f.file_field :image %\u003e\n  \u003c%= f.submit %\u003e\n\u003c% end %\u003e\n```\n\nWhen the form is submitted, in your controller you can assign the file from\nrequest params to the attachment attribute on the model:\n\n```rb\nclass PhotosController \u003c ApplicationController\n  def create\n    Photo.create(photo_params) # attaches the uploaded file\n    # ...\n  end\n\n  private\n\n  def photo_params\n    params.require(:photo).permit(:image)\n  end\nend\n```\n\nOnce a file is uploaded and attached to the record, you can retrieve the file\nURL and display it on the page:\n\n```erb\n\u003c%= image_tag @photo.image_url %\u003e\n```\n\nSee the **[Getting Started guide]** for further documentation.\n\n## Inspiration\n\nShrine was heavily inspired by [Refile] and [Roda]. From Refile it borrows the\nidea of \"backends\" (here named \"storages\"), attachment interface, and direct\nuploads. From Roda it borrows the implementation of an extensible plugin\nsystem.\n\n## Similar libraries\n\n* Paperclip\n* CarrierWave\n* Dragonfly\n* Refile\n* Active Storage\n\n## Contributing\n\nPlease refer to the [contributing page][Contributing].\n\n## Code of Conduct\n\nEveryone interacting in the Shrine project’s codebases, issue trackers, and\nmailing lists is expected to follow the [Shrine code of conduct][CoC].\n\n## License\n\nThe gem is available as open source under the terms of the [MIT License].\n\n[Shrine]: https://shrinerb.com\n[Advantages of Shrine]: https://shrinerb.com/docs/advantages\n[plugin system]: https://shrinerb.com/docs/getting-started#plugin-system\n[Retrieving Uploads]: https://shrinerb.com/docs/retrieving-uploads\n[FileSystem]: https://shrinerb.com/docs/storage/file-system\n[S3]: https://shrinerb.com/docs/storage/s3\n[GCS]: https://github.com/renchap/shrine-google_cloud_storage\n[Cloudinary]: https://github.com/shrinerb/shrine-cloudinary\n[Sequel]: https://shrinerb.com/docs/plugins/sequel\n[ActiveRecord]: https://shrinerb.com/docs/plugins/activerecord\n[ROM]: https://github.com/shrinerb/shrine-rom\n[Hanami]: https://github.com/katafrakt/hanami-shrine\n[Mongoid]: https://github.com/shrinerb/shrine-mongoid\n[eagerly]: https://shrinerb.com/docs/getting-started#eager-processing\n[on-the-fly]: https://shrinerb.com/docs/getting-started#on-the-fly-processing\n[ImageMagick]: https://github.com/janko/image_processing/blob/master/doc/minimagick.md#readme\n[libvips]: https://github.com/janko/image_processing/blob/master/doc/vips.md#readme\n[validation]: https://shrinerb.com/docs/validation\n[metadata]: https://shrinerb.com/docs/metadata\n[simple upload]: https://shrinerb.com/docs/getting-started#simple-direct-upload\n[presigned upload]: https://shrinerb.com/docs/getting-started#presigned-direct-upload\n[resumable upload]: https://shrinerb.com/docs/getting-started#resumable-direct-upload\n[Uppy]: https://uppy.io/\n[uppy-s3_multipart]: https://github.com/janko/uppy-s3_multipart\n[tus-ruby-server]: https://github.com/janko/tus-ruby-server\n[backgrounding]: https://shrinerb.com/docs/plugins/backgrounding\n[Backgrounding Libraries]: https://github.com/shrinerb/shrine/wiki/Backgrounding-Libraries\n[Getting Started guide]: https://shrinerb.com/docs/getting-started\n[roda demo]: /demo\n[rails demo]: https://github.com/erikdahlstrand/shrine-rails-example\n[Refile]: https://github.com/refile/refile\n[Roda]: https://github.com/jeremyevans/roda\n[CoC]: /CODE_OF_CONDUCT.md\n[MIT License]: /LICENSE.txt\n[Contributing]: https://github.com/shrinerb/shrine/blob/master/CONTRIBUTING.md\n[gin index]: https://www.postgresql.org/docs/current/datatype-json.html#JSON-INDEXING\n","funding_links":["https://github.com/sponsors/janko","https://opencollective.com/shrine"],"categories":["Ruby","Uncategorized","File uploaders"],"sub_categories":["Uncategorized"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fshrinerb%2Fshrine","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fshrinerb%2Fshrine","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fshrinerb%2Fshrine/lists"}