PageSourceSearch

https://shrinerb.com/assets/js/981a5161.8095a137.js

js shrinerb.com collected 2026-10-03 23:14:05 UTC 19,079 bytes, 1 lines download raw bytes

1"use strict";(self.webpackChunk=self.webpackChunk||[]).push([[7535],{1560(e,s,l){l.r(s),l.d(s,{assets:()=>i,contentTitle:()=>t,default:()=>h,frontMatter:()=>o,metadata:()=>n,toc:()=>c});const n=JSON.parse('{"id":"changing-storage","title":"Migrating File Storage","description":"This guides shows how to move file attachments to a different storage in","source":"@site/../doc/changing_storage.md","sourceDirName":".","slug":"/changing-storage","permalink":"/docs/changing-storage","draft":false,"unlisted":false,"editUrl":"https://github.com/shrinerb/shrine/edit/master/doc/../doc/changing_storage.md","tags":[],"version":"current","lastUpdatedBy":"Janko Marohni\u0107","lastUpdatedAt":1789922805000,"frontMatter":{"id":"changing-storage","title":"Migrating File Storage"},"sidebar":"guides","previous":{"title":"Migrating File Locations","permalink":"/docs/changing-location"},"next":{"title":"Writing a Plugin","permalink":"/docs/creating-plugins"}}');var r=l(4848),a=l(8453);const o={id:"changing-storage",title:"Migrating File Storage"},t=void 0,i={},c=[{value:"1. Mirror upload and delete operations",id:"1-mirror-upload-and-delete-operations",level:2},{value:"2. Copy the files",id:"2-copy-the-files",level:2},{value:"3. Update storage",id:"3-update-storage",level:2},{value:"4. Remove mirroring",id:"4-remove-mirroring",level:2}];function d(e){const s={a:"a",code:"code",figure:"figure",h2:"h2",p:"p",pre:"pre",span:"span",...(0,a.R)(),...e.components};return(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)(s.p,{children:"This guides shows how to move file attachments to a different storage in\nproduction, with zero downtime."}),"\n",(0,r.jsxs)(s.p,{children:["Let's assume we have a ",(0,r.jsx)(s.code,{children:"Photo"})," model with an ",(0,r.jsx)(s.code,{children:"image"})," file attachment stored\nin AWS S3 storage:"]}),"\n",(0,r.jsx)(s.figure,{"data-rehype-pretty-code-figure":"",children:(0,r.jsx)(s.pre,{style:{backgroundColor:"#282A36",color:"#f6f6f4"},tabIndex:"0","data-language":"rb","data-theme":"dracula-soft",children:(0,r.jsxs)(s.code,{"data-language":"rb","data-theme":"dracula-soft",style:{display:"grid"},children:[(0,r.jsxs)(s.span,{"data-line":"",children:[(0,r.jsx)(s.span,{style:{color:"#97E1F1",fontStyle:"italic"},children:"Shrine"}),(0,r.jsx)(s.span,{style:{color:"#F6F6F4"},children:"."}),(0,r.jsx)(s.span,{style:{color:"#62E884"},children:"storages"}),(0,r.jsx)(s.span,{style:{color:"#F286C4"},children:" ="}),(0,r.jsx)(s.span,{style:{color:"#F6F6F4"},children:" {"})]}),"\n",(0,r.jsxs)(s.span,{"data-line":"",children:[(0,r.jsx)(s.span,{style:{color:"#BF9EEE"}
1,children:"  cache:"}),(0,r.jsx)(s.span,{style:{color:"#97E1F1",fontStyle:"italic"},children:" Shrine"}),(0,r.jsx)(s.span,{style:{color:"#F286C4"},children:"::"}),(0,r.jsx)(s.span,{style:{color:"#97E1F1",fontStyle:"italic"},children:"Storage"}),(0,r.jsx)(s.span,{style:{color:"#F286C4"},children:"::"}),(0,r.jsx)(s.span,{style:{color:"#97E1F1",fontStyle:"italic"},children:"S3"}),(0,r.jsx)(s.span,{style:{color:"#F6F6F4"},children:"."}),(0,r.jsx)(s.span,{style:{color:"#F286C4"},children:"new"}),(0,r.jsx)(s.span,{style:{color:"#F6F6F4"},children:"(...),"})]}),"\n",(0,r.jsxs)(s.span,{"data-line":"",children:[(0,r.jsx)(s.span,{style:{color:"#BF9EEE"},children:"  store:"}),(0,r.jsx)(s.span,{style:{color:"#97E1F1",fontStyle:"italic"},children:" Shrine"}),(0,r.jsx)(s.span,{style:{color:"#F286C4"},children:"::"}),(0,r.jsx)(s.span,{style:{color:"#97E1F1",fontStyle:"italic"},children:"Storage"}),(0,r.jsx)(s.span,{style:{color:"#F286C4"},children:"::"}),(0,r.jsx)(s.span,{style:{color:"#97E1F1",fontStyle:"italic"},children:"S3"}),(0,r.jsx)(s.span,{style:{color:"#F6F6F4"},children:"."}),(0,r.jsx)(s.span,{style:{color:"#F286C4"},children:"new"}),(0,r.jsx)(s.span,{style:{color:"#F6F6F4"},children:"(...),"})]}),"\n",(0,r.jsx)(s.span,{"data-line":"",children:(0,r.jsx)(s.span,{style:{color:"#F6F6F4"},children:"}"})}),"\n",(0,r.jsx)(s.span,{"data-line":"",children:" "}),"\n",(0,r.jsxs)(s.span,{"data-line":"",children:[(0,r.jsx)(s.span,{style:{color:"#97E1F1",fontStyle:"italic"},children:"Shrine"}),(0,r.jsx)(s.span,{style:{color:"#F6F6F4"},children:"."}),(0,r.jsx)(s.span,{style:{color:"#62E884"},children:"plugin"}),(0,r.jsx)(s.span,{style:{color:"#BF9EEE"},children:" :activerecord"})]})]})})}),"\n",(0,r.jsx)(s.figure,{"data-rehype-pretty-code-figure":"",children:(0,r.jsx)(s.pre,{style:{backgroundColor:"#282A36",color:"#f6f6f4"},tabIndex:"0","data-language":"rb","data-theme":"dracula-soft",children:(0,r.jsxs)(s.code,{"data-language":"rb","data-theme":"dracula-soft",style:{display:"grid"},children:[(0,r.jsxs)(s.span,{"data-line":"",children:[(0,r.jsx)(s.span,{style:{color:"#F286C4"},children:"class"}),(0,r.jsx)(s.span,{style:{color:"#BF9EEE"},children:" ImageUploader"}),(0,r.jsx)(s.span,{style:{color:"#F286C4"},children:" <"}),(0,r.jsx)(s.span,{style:{color:"#BF9EEE"},children:" Shrine"})]}),"\n",(0,r.jsx)(s.span,{"data-line":"",children:(0,r.jsx)(s.span,{style:{color:"#7B7F8B"},children:"  # ..."})}),"\n",(0,r.jsx)(s.span,{"data-line":"",children:(0,r.jsx)(s.span,{style:{color:"#F286C4"},children:"end"})})]})})}),"\n",(0,r.jsx)(s.figure,{"data-rehype-pretty-code-figure":"",children:(0,r.jsx)(s.pre,{style:{backgroundColor:"#282A36",color:"#f6f6f4"},tabIndex:"0","data-language":"rb","data-theme":"dracula-soft",children:(0,r.jsxs)(s.code,{"data-language":"rb","data-theme":"dracula-soft",style:{display:"grid"},children:[(0,r.jsxs)(s.span,{"data-line":"",children:[(0,r.jsx)(s.span,{style:{color:"#F286C4"},children:"class"}),(0,r.jsx)(s.span,{style:{color:"#BF9EEE"},children:" Photo"}),(0,r.jsx)(s.span,{style:{color:"#F286C4"},children:" <"}),(0,r.jsx)(s.span,{style:{color:"#97E1F1",fontStyle:"italic"},children:" ActiveRecord"}),(0,r.jsx)(s.span,{style:{color:"#F286C4"},children:"::"}),(0,r.jsx)(s.span,{style:{color:"#BF9EEE"},children:"Base"})]}),"\n",(0,r.jsxs)(s.span,{"data-line":"",children:[(0,r.jsx)(s.span,{style:{color:"#F286C4"},children:"  include"}),(0,r.jsx)(s.span,{style:{color:"#97E1F1",fontStyle:"italic"},children:" ImageUploader"}),(0,r.jsx)(s.span,{style:{color:"#F286C4"},children:"::"}),(0,r.jsx)(s.span,{style:{color:"#BF9EEE"},children:"Attachment"}),(0,r.jsx)(s.span,{style:{color:"#F6F6F4"},children:"("}),(0,r.jsx)(s.span,{style:{color:"#BF9EEE"},children:":image"}),(0,r.jsx)(s.span,{style:{color:"#F6F6F4"},children:")"})]}),"\n",(0,r.jsx)(s.span,{"data-line":"",children:(0,r.jsx)(s.span,{style:{color:"#F286C4"},children:"end"})})]})})}),"\n",(0,r.jsxs)(s.p,{children:["Let's also assume that we're migrating from AWS S3 to Google Cloud Storage, and\nwe've added the new storage to ",(0,r.jsx)(s.code,{children:"Shrine.storages"}),":"]}),"\n",(0,r.jsx)(s.figure,{"data-rehype-pretty-code-figure":"",children:(0,r.jsx)(s.pre,{style:{backgroundColor:"#282A36",color:"#f6f6f4"},tabIndex:"0","data-language":"rb","data-theme":"dracula-soft",children:(0,r.jsxs)(s.code,{"data-language":"rb","data-theme":"dracula-soft",style:{display:"grid"},children:[(0,r.jsxs)(s.span,{"data-line":"",children:[(0,r.jsx)(s.span,{style:{color:"#97E1F1",fontStyle:"italic"},children:"Shrine"}),(0,r.jsx)(s.span,{style:{color:"#F6F6F4"},children:"."}),(0,r.jsx)(s.span,{style:{color:"#62E884"},children:"storages"}),(0,r.jsx)(s.span,{style:{color:"#F286C4"},children:" ="}),(0,r.jsx)(s.span,{style:{color:"#F6F6F4"},children:" {"})]}),"\n",(0,r.jsx)(s.span,{"data-line":"",children:(0,r.jsx)(s.span,{style:{color:"#F6F6F4"},children:"  ..."})}),"\n",(0,r.jsxs)(s.span,{"data-line":"",children:[(0,r.jsx)(s.span,{style:{color:"#BF9EEE"},children:"  store:"}),(0,r.jsx)(s.span,{style:{color:"#97E1F1",fontStyle:"italic"},children:" Shrine"}),(0,r.jsx)(s.span,{style:{color:"#F286C4"},children:"::"}),(0,r.jsx)(s.span,{style:{color:"#97E1F1",fontStyle:"italic"},children:"Storage"}),(0,r.jsx)(s.span,{style:{color:"#F286C4"},children:"::"}),(0,r.jsx)(s.span,{style:{color:"#97E1F1",fontStyle:"italic"},children:"S3"}),(0,r.jsx)(s.span,{style:{color:"#F6F6F4"},children:"."}),(0,r.jsx)(s.span,{style:{color:"#F286C4"},children:"new"}),(0,r.jsx)(s.span,{style:{color:"#F6F6F4"},children:"(...),"})]}),"\n",(0,r.jsxs)(s.span,{"data-line":"",children:[(0,r.jsx)(s.span,{style:{color:"#BF9EEE"},children:"  gcs:"}),(0,r.jsx)(s.span,{style:{color:"#97E1F1",fontStyle:"italic"},children:"   Shrine"}),(0,r.jsx)(s.span,{style:{color:"#F286C4"},children:"::"}),(0,r.jsx)(s.span,{style:{color:"#97E1F1",fontStyle:"italic"},children:"Storage"}),(0,r.jsx)(s.span,{style:{color:"#F286C4"},children:"::"}),(0,r.jsx)(s.span,{style:{color:"#97E1F1",fontStyle:"italic"},children:"GoogleCloudStorage"}),(0,r.jsx)(s.span,{style:{color:"#F6F6F4"},children:"."}),(0,r.jsx)(s.span,{style:{color:"#F286C4"},children:"new"}),(0,r.jsx)(s.span,{style:{color:"#F6F6F4"},children:"(...),"})]}),"\n",(0,r.jsx)(s.span,{"data-line":"",children:(0,r.jsx)(s.span,{style:{color:"#F6F6F4"},children:"}"})})]})})}),"\n",(0,r.jsx)(s.h2,{id:"1-mirror-upload-and-delete-operations",children:"1. Mirror upload and delete operations"}),"\n",(0,r.jsxs)(s.p,{children:["The first step is to start mirroring uploads and deletes made on your current\nstorage to the new storage. We can do this by loading the ",(0,r.jsx)(s.code,{children:"mirroring"})," plugin:"]}),"\n",(0,r.jsx)(s.figure,{"data-rehype-pretty-code-figure":"",children:(0,r.jsx)(s.pre,{style:{backgroundColor:"#282A36",color:"#f6f6f4"},tabIndex:"0","data-language":"rb","data-theme":"dracula-soft",children:(0,r.jsx)(s.code,{"data-language":"rb","data-theme":"dracula-soft",style:{display:"grid"},children:(0,r.jsxs)(s.span,{"data-line":"",children:[(0,r.jsx)(s.span,{style:{color:"#97E1F1",fontStyle:"italic"},children:"Shrine"}),(0,r.jsx)(s.span,{style:{color:"#F6F6F4"},children:"."}),(0,r.jsx)(s.span,{style:{color:"#62E884"},children:"plugin"}),(0,r.jsx)(s.span,{style:{color:"#BF9EEE"},children:" :mirroring"}),(0,r.jsx)(s.span,{style:{color:"#F6F6F4"},children:", "}),(0,r.jsx)(s.span,{style:{color:"#BF9EEE"},children:"mirror:"}),(0,r.jsx)(s.span,{style:{color:"#F6F6F4"},children:" { "}),(0,r.jsx)(s.span,{style:{color:"#BF9EEE"},children:"store:"}),(0,r.jsx)(s.span,{style:{color:"#BF9EEE"},children:" :gcs"}),(0,r.jsx)(s.span,{style:{color:"#F6F6F4"},children:" }"})]})})})}),"\n",(0,r.jsx)(s.p,{children:"Put the above code in an initializer and deploy it."}),"\n",(0,r.jsxs)(s.p,{children:["You can additionally delay the mirroring into a ",(0,r.jsx)(s.a,{href:"https://shrinerb.com/docs/plugins/mirroring#backgrounding",children:"background job"})," for better performance."]}),"\n",(0,r.jsx)(s.h2,{id:"2-copy-the-files",children:"2. Copy the files"}),"\n",(0,r.jsx)(s.p,{children:"Next step is to copy all remaining files from current storage into the new\nstorage using the following script. It fetches the photos in batches, downloads\nthe image, and re-uploads it to the new storage."}),"\n",(0,r.jsx)(s.figure,{"data-rehype-pretty-code-figure":"",children:(0,r.jsx)(s.pre,{style:{backgroundColor:"#282A36",color:"#f6f6f4"},tabIndex:"0","data-language":"rb","data-theme":"dracula-soft",children:(0,r.jsxs)(s.code,{"data-language":"rb","data-theme":"dracula-soft",style:{display:"grid"},children:[(0,r.jsxs)(s.span,{"data-line":"",children:[(0,r.jsx)(s.span,{style:{color:"#97E1F1",fontStyle:"italic"},children:"Photo"}),(0,r.jsx)(s.span,{style:{color:"#F6F6F4"},children:"."}),(0,r.jsx)(s.span,{style:{color:"#62E884"},children:"find_each"}),(0,r.jsx)(s.span,{style:{color:"#F286C4"},children:" do"}),(0,r.jsx)(s.span,{style:{color:"#F6F6F4"},children:" |photo|"})]}),"\n",(0,r.jsxs)(s.span,{"data-line":"",children:[(0,r.jsx)(s.span,{style:{color:"#F6F6F4"},children:"  attacher = photo."}),(0,r.jsx)(s.span,{style:{color:"#62E884"},children:"image_attacher"})]}),"\n",(0,r.jsx)(s.span,{"data-line":"",children:" "}),"\n",(0,r.jsxs)(s.span,{"data-line":"",children:[(0,r.jsx)(s.span,{style:{color:"#F286C4"},children:"  next"}),(0,r.jsx)(s.span,{style:{color:"#F286C4"},children:" unless"}),(0,r.jsx)(s.span,{style:{color:"#F6F6F4"},children:" attacher."}),(0,r.jsx)(s.span,{style:{color:"#62E884"},children:"stored?"})]}),"\n",(0,r.jsx)(s.span,{"data-line":"",children:" "}),"\n",(0,r.jsxs)(s.span,{"data-line":"",children:[(0,r.jsx)(s.span,{style:{color:"#F6F6F4"},children:"  attacher."}),(0,r.jsx)(s.span,{style:{color:"#62E884"},children:"file"}),(0,r.jsx)(s.span,{style:{color:"#F6F6F4"},children:"."}),(0,r.jsx)(s.span,{style:{color:"#62E884"},children:"trigger_mirror_upload"})]}),"\n",(0,r.jsx)(s.span,{"data-line":"",children:" "}),"\n",(0,r.jsx)(s.span,{"data-line":"",children:(0,r.jsx)(s.span,{style:{color:"#7B7F8B"},children:"  # if using derivatives"})}),"\n",(0,r.jsxs)(s.span,{"data-line":"",children:[(0,r.jsx)(s.span,{style:{color:"#F6F6F4"},children:"  attacher."}),(0,r.jsx)(s.span,{style:{color:"#62E884"},children:"map_derivative"}),(0,r.jsx)(s.span,{style:{color:"#F6F6F4"},children:"(attacher."}),(0,r.jsx)(s.span,{style:{color:"#62E884"},children:"derivatives"}),(0,r.jsx)(s.span,{style:{color:"#F6F6F4"},children:") "}),(0,r.jsx)(s.span,{style:{color:"#F286C4"},children:"do"}),(0,r.jsx)(s.span,{style:{color:"#F6F6F4"},children:" |"}),(0,r.jsx)(s.span,{style:{color:"#BF9EEE"},children:"_"}),(0,r.jsx)(s.span,{style:{color:"#F6F6F4"},children:", derivative|"})]}),"\n",(0,r.jsxs)(s.span,{"data-line":"",children:[(0,r.jsx)(s.span,{style:{color:"#F6F6F4"},children:"    derivative."}),(0,r.jsx)(s.span,{style:{color:"#62E884"},children:"trigger_mirror_upload"})]}),"\n",(0,r.jsx)(s.span,{"data-line":"",children:(0,r.jsx)(s.span,{style:{color:"#F286C4"},children:"  end"})}),"\n",(0,r.jsx)(s.span,{"data-line":"",children:(0,r.jsx)(s.span,{style:{color:"#F286C4"},children:"end"})})]})})}),"\n",(0,r.jsx)(s.p,{children:"Now the new storage should have all files the current storage has, and new\nuploads will continue being mirrored to the new storage."}),"\n",(0,r.jsx)(s.h2,{id:"3-update-storage",children:"3. Update storage"}),"\n",(0,r.jsx)(s.p,{children:"Once all the files are copied over to the new storage, everything should be\nready for us to update the storage in the Shrine configuration. We can keep\nmirroring, in case the change would need to reverted."}),"\n",(0,r.jsx)(s.figure,{"data-rehype-pretty-code-figure":"",children:(0,r.jsx)(s.pre,{style:{backgroundColor:"#282A36",color:"#f6f6f4"},tabIndex:"0","data-language":"rb","data-theme":"dracula-soft",children:(0,r.jsxs)(s.code,{"data-language":"rb","data-theme":"dracula-soft",style:{display:"grid"},children:[(0,r.jsxs)(s.span,{"data-line":"",children:[(0,r.jsx)(s.span,{style:{color:"#97E1F1",fontStyle:"italic"},children:"Shrine"}),(0,r.jsx)(s.span,{style:{color:"#F6F6F4"},children:"."}),(0,r.jsx)(s.span,{style:{color:"#62E884"},children:"storages"}),(0,r.jsx)(s.span,{style:{color:"#F286C4"},children:" ="}),(0,r.jsx)(s.span,{style:{color:"#F6F6F4"},children:" {"})]}),"\n",(0,r.jsx)(s.span,{"data-line":"",children:(0,r.jsx)(s.span,{style:{color:"#F6F6F4"},children:"  ..."})}),"\n",(0,r.jsxs)(s.span,{"data-line":"",children:[(0,r.jsx)(s.span,{style:{color:"#BF9EEE"},children:"  store:"}),(0,r.jsx)(s.span,{style:{color:"#97E1F1",fontStyle:"italic"},children:" Shrine"}),(0,r.jsx)(s.span,{style:{color:"#F286C4"},children:"::"}),(0,r.jsx)(s.span,{style:{color:"#97E1F1",fontStyle:"italic"},children:"Storage"}),(0,r.jsx)(s.span,{style:{color:"#F286C4"},children:"::"}),(0,r.jsx)(s.span,{style:{color:"#97E1F1",fontStyle:"italic"},children:"GoogleCloudStorage"}),(0,r.jsx)(s.span,{style:{color:"#F6F6F4"},children:"."}),(0,r.jsx)(s.span,{style:{color:"#F286C4"},children:"new"}),(0,r.jsx)(s.span,{style:{color:"#F6F6F4"},children:"(...),"})]}),"\n",(0,r.jsxs)(s.span,{"data-line":"",children:[(0,r.jsx)(s.span,{style:{color:"#BF9EEE"},children:"  s3:"}),(0,r.jsx)(s.span,{style:{color:"#97E1F1",fontStyle:"italic"},children:"    Shrine"}),(0,r.jsx)(s.span,{style:{color:"#F286C4"},children:"::"}),(0,r.jsx)(s.span,{style:{color:"#97E1F1",fontStyle:"italic"},children:"Storage"}),(0,r.jsx)(s.span,{style:{color:"#F286C4"},children:"::"}),(0,r.jsx)(s.span,{style:{color:"#97E1F1",fontStyle:"italic"},children:"S3"}),(0,r.jsx)(s.span,{style:{color:"#F6F6F4"},children:"."}),(0,r.jsx)(s.span,{style:{color:"#F286C4"},children:"new"}),(0,r.jsx)(s.span,{style:{color:"#F6F6F4"},children:"(...),"})]}),"\n",(0,r.jsx)(s.span,{"data-line":"",children:(0,r.jsx)(s.span,{style:{color:"#F6F6F4"},children:"}"})}),"\n",(0,r.jsx)(s.span,{"data-line":"",children:" "}),"\n",(0,r.jsxs)(s.span,{"data-line":"",children:[(0,r.jsx)(s.span,{style:{color:"#97E1F1",fontStyle:"italic"},children:"Shrine"}),(0,r.jsx)(s.span,{style:{color:"#F6F6F4"},children:"."}),(0,r.jsx)(s.span,{style:{color:"#62E884"},children:"plugin"}),(0,r.jsx)(s.span,{style:{color:"#BF9EEE"},children:" :mirroring"}),(0,r.jsx)(s.span,{style:{color:"#F6F6F4"},children:", "}),(0,r.jsx)(s.span,{style:{color:"#BF9EEE"},children:"mirror:"}),(0,r.jsx)(s.span,{style:{color:"#F6F6F4"},children:" { "}),(0,r.jsx)(s.span,{style:{color:"#BF9EEE"},children:"store:"}),(0,r.jsx)(s.span,{style:{color:"#BF9EEE"},children:" :s3"}),(0,r.jsx)(s.span,{style:{color:"#F6F6F4"},children:" } "}),(0,r.jsx)(s.span,{style:{color:"#7B7F8B"},children:"# mirror to :s3 storage"})]})]})})}),"\n",(0,r.jsx)(s.h2,{id:"4-remove-mirroring",children:"4. Remove mirroring"}),"\n",(0,r.jsx)(s.p,{children:"Once everything is looking good, we can remove the mirroring:"}),"\n",(0,r.jsx)(s.figure,{"data-rehype-pretty-code-figure":"",children:(0,r.jsx)(s.pre,{style:{backgroundColor:"#282A36",color:"#f6f6f4"},tabIndex:"0","data-language":"diff","data-theme":"dracula-soft",children:(0,r.jsxs)(s.code,{"data-language":"diff","data-theme":"dracula-soft",style:{display:"grid"},children:[(0,r.jsx)(s.span,{"data-line":"",children:(0,r.jsx)(s.span,{style:{color:"#F6F6F4"},children:"Shrine.storages = {"})}),"\n",(0,r.jsx)(s.span,{"data-line":"",children:(0,r.jsx)(s.span,{style:{color:"#F6F6F4"},children:"  ..."})}),"\n",(0,r.jsx)(s.span,{"data-line":"",children:(0,r.jsx)(s.span,{style:{color:"#F6F6F4"},children:"  store: Shrine::Storage::GoogleCloudStorage.new(...),"})}),"\n",(0,r.jsx)(s.span,{"data-line":"",children:(0,r.jsx)(s.span,{style:{color:"#EE6666"},children:"- s3:    Shrine::Storage::S3.new(...),"})}),"\n",(0,r.jsx)(s.span,{"data-line":"",children:(0,r.jsx)(s.span,{style:{color:"#F6F6F4"},children:"}"})}),"\n",(0,r.jsx)(s.span,{"data-line":"",children:" "}),"\n",(0,r.jsx)(s.span,{"data-line":"",children:(0,r.jsx)(s.span,{style:{color:"#EE6666"},children:"- Shrine.plugin :mirroring, mirror: { store: :s3 } # mirror to :s3 storage"})})]})})})]})}function h(e={}){const{wrapper:s}={...(0,a.R)(),...e.components};return s?(0,r.jsx)(s,{...e,children:(0,r.jsx)(d,{...e})}):d(e)}},8453(e,s,l){l.d(s,{R:()=>o,x:()=>t});var n=l(6540);const r={},a=n.createContext(r);function o(e){const s=n.useContext(a);return n.useMemo(function(){return"function"==typeof e?e(s):{...s,...e}},[s,e])}function t(e){let s;return s=e.disableParentContext?"function"==typeof e.components?e.
1components(r):e.components||r:o(e.components),n.createElement(a.Provider,{value:s},e.children)}}}]);

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.