shrine 2.19.3 → 3.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (211) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +523 -41
  3. data/LICENSE.txt +1 -1
  4. data/README.md +83 -979
  5. data/doc/advantages.md +231 -204
  6. data/doc/attacher.md +304 -153
  7. data/doc/carrierwave.md +297 -226
  8. data/doc/changing_derivatives.md +308 -0
  9. data/doc/changing_location.md +103 -21
  10. data/doc/changing_storage.md +110 -0
  11. data/doc/creating_persistence_plugins.md +132 -0
  12. data/doc/creating_plugins.md +43 -23
  13. data/doc/creating_storages.md +19 -5
  14. data/doc/design.md +147 -97
  15. data/doc/direct_s3.md +38 -28
  16. data/doc/external/articles.md +63 -0
  17. data/doc/external/extensions.md +53 -0
  18. data/doc/external/misc.md +32 -0
  19. data/doc/getting_started.md +1156 -0
  20. data/doc/metadata.md +190 -109
  21. data/doc/multiple_files.md +93 -30
  22. data/doc/paperclip.md +384 -262
  23. data/doc/plugins/activerecord.md +177 -46
  24. data/doc/plugins/add_metadata.md +139 -38
  25. data/doc/plugins/atomic_helpers.md +217 -0
  26. data/doc/plugins/backgrounding.md +156 -98
  27. data/doc/plugins/cached_attachment_data.md +7 -5
  28. data/doc/plugins/column.md +121 -0
  29. data/doc/plugins/data_uri.md +23 -22
  30. data/doc/plugins/default_storage.md +36 -10
  31. data/doc/plugins/default_url.md +30 -13
  32. data/doc/plugins/delete_raw.md +4 -2
  33. data/doc/plugins/derivation_endpoint.md +186 -101
  34. data/doc/plugins/derivatives.md +839 -0
  35. data/doc/plugins/determine_mime_type.md +4 -2
  36. data/doc/plugins/download_endpoint.md +64 -8
  37. data/doc/plugins/dynamic_storage.md +5 -3
  38. data/doc/plugins/entity.md +263 -0
  39. data/doc/plugins/form_assign.md +55 -0
  40. data/doc/plugins/included.md +31 -8
  41. data/doc/plugins/infer_extension.md +21 -10
  42. data/doc/plugins/instrumentation.md +38 -16
  43. data/doc/plugins/keep_files.md +16 -17
  44. data/doc/plugins/metadata_attributes.md +42 -13
  45. data/doc/plugins/mirroring.md +118 -0
  46. data/doc/plugins/model.md +210 -0
  47. data/doc/plugins/module_include.md +4 -2
  48. data/doc/plugins/multi_cache.md +24 -0
  49. data/doc/plugins/persistence.md +101 -0
  50. data/doc/plugins/presign_endpoint.md +9 -4
  51. data/doc/plugins/pretty_location.md +16 -3
  52. data/doc/plugins/processing.md +4 -2
  53. data/doc/plugins/rack_file.md +8 -2
  54. data/doc/plugins/rack_response.md +6 -2
  55. data/doc/plugins/recache.md +4 -2
  56. data/doc/plugins/refresh_metadata.md +49 -9
  57. data/doc/plugins/remote_url.md +84 -47
  58. data/doc/plugins/remove_attachment.md +27 -6
  59. data/doc/plugins/remove_invalid.md +21 -6
  60. data/doc/plugins/restore_cached_data.md +11 -3
  61. data/doc/plugins/sequel.md +159 -35
  62. data/doc/plugins/signature.md +16 -5
  63. data/doc/plugins/store_dimensions.md +14 -2
  64. data/doc/plugins/tempfile.md +4 -2
  65. data/doc/plugins/type_predicates.md +96 -0
  66. data/doc/plugins/upload_endpoint.md +13 -13
  67. data/doc/plugins/upload_options.md +6 -4
  68. data/doc/plugins/{default_url_options.md → url_options.md} +9 -7
  69. data/doc/plugins/validation.md +97 -0
  70. data/doc/plugins/validation_helpers.md +16 -13
  71. data/doc/plugins/versions.md +15 -19
  72. data/doc/processing.md +438 -221
  73. data/doc/refile.md +188 -170
  74. data/doc/release_notes/1.0.0.md +4 -0
  75. data/doc/release_notes/1.1.0.md +6 -2
  76. data/doc/release_notes/1.2.0.md +4 -0
  77. data/doc/release_notes/1.3.0.md +4 -0
  78. data/doc/release_notes/1.4.0.md +4 -0
  79. data/doc/release_notes/1.4.1.md +4 -0
  80. data/doc/release_notes/1.4.2.md +4 -0
  81. data/doc/release_notes/2.0.0.md +4 -0
  82. data/doc/release_notes/2.0.1.md +4 -0
  83. data/doc/release_notes/2.1.0.md +5 -1
  84. data/doc/release_notes/2.1.1.md +4 -0
  85. data/doc/release_notes/2.10.0.md +4 -0
  86. data/doc/release_notes/2.10.1.md +4 -0
  87. data/doc/release_notes/2.11.0.md +4 -0
  88. data/doc/release_notes/2.12.0.md +4 -0
  89. data/doc/release_notes/2.13.0.md +4 -0
  90. data/doc/release_notes/2.14.0.md +5 -1
  91. data/doc/release_notes/2.15.0.md +11 -7
  92. data/doc/release_notes/2.16.0.md +4 -0
  93. data/doc/release_notes/2.17.0.md +4 -0
  94. data/doc/release_notes/2.18.0.md +4 -0
  95. data/doc/release_notes/2.19.0.md +6 -3
  96. data/doc/release_notes/2.2.0.md +4 -0
  97. data/doc/release_notes/2.3.0.md +4 -0
  98. data/doc/release_notes/2.3.1.md +4 -0
  99. data/doc/release_notes/2.4.0.md +4 -0
  100. data/doc/release_notes/2.4.1.md +4 -0
  101. data/doc/release_notes/2.5.0.md +4 -0
  102. data/doc/release_notes/2.6.0.md +4 -0
  103. data/doc/release_notes/2.6.1.md +4 -0
  104. data/doc/release_notes/2.7.0.md +4 -0
  105. data/doc/release_notes/2.8.0.md +4 -0
  106. data/doc/release_notes/2.9.0.md +4 -0
  107. data/doc/release_notes/3.0.0.md +981 -0
  108. data/doc/release_notes/3.0.1.md +22 -0
  109. data/doc/release_notes/3.1.0.md +73 -0
  110. data/doc/release_notes/3.2.0.md +96 -0
  111. data/doc/release_notes/3.2.1.md +31 -0
  112. data/doc/release_notes/3.2.2.md +14 -0
  113. data/doc/release_notes/3.3.0.md +105 -0
  114. data/doc/release_notes/3.4.0.md +35 -0
  115. data/doc/release_notes/3.5.0.md +63 -0
  116. data/doc/release_notes/3.6.0.md +23 -0
  117. data/doc/retrieving_uploads.md +5 -2
  118. data/doc/securing_uploads.md +60 -37
  119. data/doc/storage/file_system.md +20 -3
  120. data/doc/storage/memory.md +19 -0
  121. data/doc/storage/s3.md +122 -78
  122. data/doc/testing.md +141 -133
  123. data/doc/upgrading_to_3.md +708 -0
  124. data/doc/validation.md +54 -90
  125. data/lib/shrine/attacher.rb +292 -169
  126. data/lib/shrine/attachment.rb +13 -46
  127. data/lib/shrine/plugins/_persistence.rb +93 -0
  128. data/lib/shrine/plugins/activerecord.rb +77 -34
  129. data/lib/shrine/plugins/add_metadata.rb +25 -17
  130. data/lib/shrine/plugins/atomic_helpers.rb +119 -0
  131. data/lib/shrine/plugins/backgrounding.rb +77 -113
  132. data/lib/shrine/plugins/cached_attachment_data.rb +6 -15
  133. data/lib/shrine/plugins/column.rb +102 -0
  134. data/lib/shrine/plugins/data_uri.rb +38 -36
  135. data/lib/shrine/plugins/default_storage.rb +45 -15
  136. data/lib/shrine/plugins/default_url.rb +12 -24
  137. data/lib/shrine/plugins/default_url_options.rb +3 -30
  138. data/lib/shrine/plugins/delete_raw.rb +10 -16
  139. data/lib/shrine/plugins/derivation_endpoint.rb +130 -171
  140. data/lib/shrine/plugins/derivatives.rb +645 -0
  141. data/lib/shrine/plugins/determine_mime_type.rb +9 -21
  142. data/lib/shrine/plugins/download_endpoint.rb +118 -133
  143. data/lib/shrine/plugins/dynamic_storage.rb +5 -11
  144. data/lib/shrine/plugins/entity.rb +158 -0
  145. data/lib/shrine/plugins/form_assign.rb +108 -0
  146. data/lib/shrine/plugins/included.rb +6 -6
  147. data/lib/shrine/plugins/infer_extension.rb +17 -20
  148. data/lib/shrine/plugins/instrumentation.rb +59 -43
  149. data/lib/shrine/plugins/keep_files.rb +3 -15
  150. data/lib/shrine/plugins/metadata_attributes.rb +28 -19
  151. data/lib/shrine/plugins/mirroring.rb +142 -0
  152. data/lib/shrine/plugins/model.rb +160 -0
  153. data/lib/shrine/plugins/module_include.rb +3 -3
  154. data/lib/shrine/plugins/multi_cache.rb +27 -0
  155. data/lib/shrine/plugins/presign_endpoint.rb +27 -28
  156. data/lib/shrine/plugins/pretty_location.rb +15 -9
  157. data/lib/shrine/plugins/processing.rb +22 -9
  158. data/lib/shrine/plugins/rack_file.rb +2 -42
  159. data/lib/shrine/plugins/rack_response.rb +21 -10
  160. data/lib/shrine/plugins/recache.rb +6 -5
  161. data/lib/shrine/plugins/refresh_metadata.rb +13 -11
  162. data/lib/shrine/plugins/remote_url.rb +49 -49
  163. data/lib/shrine/plugins/remove_attachment.rb +12 -6
  164. data/lib/shrine/plugins/remove_invalid.rb +19 -8
  165. data/lib/shrine/plugins/restore_cached_data.rb +13 -7
  166. data/lib/shrine/plugins/sequel.rb +86 -36
  167. data/lib/shrine/plugins/signature.rb +10 -16
  168. data/lib/shrine/plugins/store_dimensions.rb +35 -40
  169. data/lib/shrine/plugins/tempfile.rb +1 -3
  170. data/lib/shrine/plugins/type_predicates.rb +113 -0
  171. data/lib/shrine/plugins/upload_endpoint.rb +28 -24
  172. data/lib/shrine/plugins/upload_options.rb +14 -15
  173. data/lib/shrine/plugins/url_options.rb +31 -0
  174. data/lib/shrine/plugins/validation.rb +80 -0
  175. data/lib/shrine/plugins/validation_helpers.rb +35 -58
  176. data/lib/shrine/plugins/versions.rb +107 -87
  177. data/lib/shrine/plugins.rb +22 -0
  178. data/lib/shrine/storage/file_system.rb +46 -64
  179. data/lib/shrine/storage/linter.rb +42 -7
  180. data/lib/shrine/storage/memory.rb +49 -0
  181. data/lib/shrine/storage/s3.rb +173 -160
  182. data/lib/shrine/uploaded_file.rb +32 -32
  183. data/lib/shrine/version.rb +3 -3
  184. data/lib/shrine.rb +87 -150
  185. data/shrine.gemspec +11 -12
  186. metadata +92 -82
  187. data/doc/migrating_storage.md +0 -76
  188. data/doc/plugins/backup.md +0 -31
  189. data/doc/plugins/copy.md +0 -24
  190. data/doc/plugins/delete_promoted.md +0 -12
  191. data/doc/plugins/direct_upload.md +0 -172
  192. data/doc/plugins/hooks.md +0 -58
  193. data/doc/plugins/logging.md +0 -42
  194. data/doc/plugins/migration_helpers.md +0 -60
  195. data/doc/plugins/moving.md +0 -19
  196. data/doc/plugins/multi_delete.md +0 -20
  197. data/doc/plugins/parallelize.md +0 -16
  198. data/doc/plugins/parsed_json.md +0 -23
  199. data/doc/regenerating_versions.md +0 -143
  200. data/lib/shrine/plugins/background_helpers.rb +0 -5
  201. data/lib/shrine/plugins/backup.rb +0 -90
  202. data/lib/shrine/plugins/copy.rb +0 -50
  203. data/lib/shrine/plugins/delete_promoted.rb +0 -20
  204. data/lib/shrine/plugins/direct_upload.rb +0 -217
  205. data/lib/shrine/plugins/hooks.rb +0 -90
  206. data/lib/shrine/plugins/logging.rb +0 -142
  207. data/lib/shrine/plugins/migration_helpers.rb +0 -70
  208. data/lib/shrine/plugins/moving.rb +0 -57
  209. data/lib/shrine/plugins/multi_delete.rb +0 -32
  210. data/lib/shrine/plugins/parallelize.rb +0 -78
  211. data/lib/shrine/plugins/parsed_json.rb +0 -29
data/doc/refile.md CHANGED
@@ -1,17 +1,22 @@
1
- # Shrine for Refile Users
1
+ ---
2
+ title: Upgrading from Refile
3
+ ---
2
4
 
3
5
  This guide is aimed at helping Refile users transition to Shrine, and it consists
4
6
  of three parts:
5
7
 
6
8
  1. Explanation of the key differences in design between Refile and Shrine
7
- 2. Instructions how to migrate and existing app that uses Refile to Shrine
9
+ 2. Instructions how to migrate an existing app that uses Refile to Shrine
8
10
  3. Extensive reference of Refile's interface with Shrine equivalents
9
11
 
10
- ## Uploaders
12
+ ## Overview
11
13
 
12
14
  Shrine borrows many great concepts from Refile: Refile's "backends" are here
13
- named "storages", it uses the same IO abstraction for uploading and representing
14
- uploaded files, similar attachment logic, and direct uploads are also supported.
15
+ named "storages", it uses the same IO abstraction for uploading and
16
+ representing uploaded files, similar attachment logic, and direct uploads are
17
+ supported as well.
18
+
19
+ ### Uploader
15
20
 
16
21
  While in Refile you work with storages directly, Shrine uses *uploaders* which
17
22
  wrap storage uploads:
@@ -25,66 +30,27 @@ uploaded_file #=> #<Shrine::UploadedFile ...>
25
30
  uploaded_file.storage #=> #<Shrine::Storage::S3>
26
31
  ```
27
32
 
28
- This way Shrine can perform tasks like generating location, extracting
33
+ This way, Shrine can perform tasks like generating location, extracting
29
34
  metadata, processing, and logging, which are all storage-agnostic, and leave
30
35
  storages to deal only with actual file storage. And these tasks can be
31
36
  configured differently depending on the types of files you're uploading:
32
37
 
33
38
  ```rb
34
39
  class ImageUploader < Shrine
35
- add_metadata :exif do |io, context|
40
+ add_metadata :exif do |io|
36
41
  MiniMagick::Image.new(io).exif
37
42
  end
38
43
  end
39
44
  ```
40
45
  ```rb
41
46
  class VideoUploader < Shrine
42
- add_metadata :duration do |io, context|
47
+ add_metadata :duration do |io|
43
48
  FFMPEG::Movie.new(io.path).duration
44
49
  end
45
50
  end
46
51
  ```
47
52
 
48
- ### Processing
49
-
50
- Refile implements on-the-fly processing, serving all files through the Rack
51
- endpoint. However, it doesn't offer any abilities for processing on upload.
52
- Shrine, on the other hand, generates URLs to specific storages and offers
53
- processing on upload (like CarrierWave and Paperclip), but doesn't support
54
- on-the-fly processing.
55
-
56
- The reason for this decision is that an image server is a completely separate
57
- responsibility, and it's better to use any of the generic services for
58
- on-the-fly processing. Shrine already has integrations for many such services:
59
- [shrine-cloudinary], [shrine-imgix], and [shrine-uploadcare]. There is even
60
- an open-source solution, [Attache], which you can also use with Shrine.
61
-
62
- This is how you would process multiple versions in Shrine:
63
-
64
- ```rb
65
- require "image_processing/mini_magick"
66
-
67
- class ImageUploader < Shrine
68
- plugin :processing
69
- plugin :versions
70
-
71
- process(:store) do |io, context|
72
- versions = { original: io } # retain original
73
-
74
- io.download do |original|
75
- pipeline = ImageProcessing::MiniMagick.source(original)
76
-
77
- versions[:large] = pipeline.resize_to_limit!(800, 800)
78
- versions[:medium] = pipeline.resize_to_limit!(500, 500)
79
- versions[:small] = pipeline.resize_to_limit!(300, 300)
80
- end
81
-
82
- versions # return the hash of processed files
83
- end
84
- end
85
- ```
86
-
87
- ### URL
53
+ #### URL
88
54
 
89
55
  While Refile serves all files through the Rack endpoint mounted in your app,
90
56
  Shrine serves files directly from storage services:
@@ -99,103 +65,113 @@ Refile.attachment_url(@photo, :image) #=> "/attachments/cache/50dfl833lfs0gfh.jp
99
65
 
100
66
  If you're using storage which don't expose files over URL (e.g. a database
101
67
  storage), or you want to secure your downloads, you can also serve files
102
- through your app using the download_endpoint plugin.
68
+ through your app using the [`download_endpoint`][download_endpoint] plugin.
103
69
 
104
- ## Attachments
70
+ ### Persistence
105
71
 
106
- While in Refile you configure attachments by passing options to `.attachment`,
107
- in Shrine you define all your uploading logic inside uploaders, and then
108
- generate an attachment module with that uploader which is included into the
109
- model:
72
+ Refile persists the uploaded file location and metadata into individual
73
+ columns:
74
+
75
+ * `<attachment>_id`
76
+ * `<attachment>_filename`
77
+ * `<attachment>_content_type`
78
+ * `<attachment>_size`
79
+
80
+ Shrine, on the other hand, saves all uploaded file data into a single
81
+ `<attachment>_data` column:
110
82
 
111
83
  ```rb
112
- class Photo < Sequel::Model
113
- extend Shrine::Sequel::Attachment
114
- attachment :image, destroy: false
115
- end
84
+ {
85
+ "id": "path/to/image.jpg",
86
+ "storage": "store",
87
+ "metadata": {
88
+ "filename": "nature.jpg",
89
+ "size": 4739472,
90
+ "mime_type": "image/jpeg"
91
+ }
92
+ }
116
93
  ```
117
-
118
94
  ```rb
119
- class ImageUploader < Shrine
120
- plugin :sequel
121
- plugin :keep_files, destroyed: true
122
- end
95
+ photo.image.id #=> "path/to/image.jpg"
96
+ photo.image.storage_key #=> :store
97
+ photo.image.metadata #=> { "filename" => "...", "size" => ..., "mime_type" => "..." }
123
98
 
124
- class Photo < Sequel::Model
125
- include ImageUploader::Attachment.new(:image)
126
- end
99
+ photo.image.original_filename #=> "nature.jpg"
100
+ photo.image.size #=> 4739472
101
+ photo.image.mime_type #=> "image/jpeg"
127
102
  ```
128
103
 
129
- This way we can encapsulate all attachment logic inside a class and share it
130
- between different models.
104
+ This column can be queried if it's made a JSON column. Alternatively, you can
105
+ use the [`metadata_attributes`][metadata_attributes] plugin to save metadata
106
+ into separate columns.
131
107
 
132
- ### Metadata
133
-
134
- Refile allows you to save additional metadata about uploaded files in additional
135
- columns, so you can define `<attachment>_filename`, `<attachment>_content_type`,
136
- or `<attachment>_size`.
108
+ ### Processing
137
109
 
138
- Shrine, on the other hand, saves all metadata into a single `<attachment>_data`
139
- column:
110
+ Shrine provides on-the-fly processing via the
111
+ [`derivation_endpoint`][derivation_endpoint] plugin:
140
112
 
141
113
  ```rb
142
- photo.image_data #=>
143
- # {
144
- # "storage" => "store",
145
- # "id" => "photo/1/image/0d9o8dk42.png",
146
- # "metadata" => {
147
- # "filename" => "nature.png",
148
- # "size" => 49349138,
149
- # "mime_type" => "image/png"
150
- # }
151
- # }
114
+ require "image_processing/mini_magick"
152
115
 
153
- photo.image.original_filename #=> "nature.png"
154
- photo.image.size #=> 49349138
155
- photo.image.mime_type #=> "image/png"
116
+ class ImageUploader < Shrine
117
+ plugin :derivation_endpoint,
118
+ secret_key: "<YOUR SECRET KEY>",
119
+ prefix: "derivations/image" # needs to match the mount point in routes
120
+
121
+ derivation :thumbnail do |file, width, height|
122
+ ImageProcessing::MiniMagick
123
+ .source(file)
124
+ .resize_to_limit!(width.to_i, height.to_i)
125
+ end
126
+ end
127
+ ```
128
+ ```rb
129
+ # config/routes.rb (Rails)
130
+ Rails.application.routes.draw do
131
+ # ...
132
+ mount ImageUploader.derivation_endpoint => "/derivations/image"
133
+ end
156
134
  ```
157
135
 
158
- By default "filename", "size" and "mime_type" is stored, but you can also store
159
- image dimensions, or define any other custom metadata. This also allow storages
160
- to add their own metadata.
136
+ Shrine also support eager processing using the [`derivatives`][derivatives]
137
+ plugin.
161
138
 
162
- ### Validations
139
+ ### Validation
163
140
 
164
- In Refile you define validations by passing options to `.attachment`, while
165
- in Shrine you define validations on the instance-level, which allows them to
166
- be dynamic:
141
+ In Refile, file validation is defined statically on attachment definition:
167
142
 
168
143
  ```rb
169
144
  class Photo < Sequel::Model
170
145
  attachment :image,
171
- extension: %w[jpg jpeg png gif],
172
- content_type: %w[image/jpeg image/png image/gif]
146
+ extension: %w[jpg jpeg png webp],
147
+ content_type: %w[image/jpeg image/png image/webp]
173
148
  end
174
149
  ```
175
150
 
151
+ In Shrine, validation is performed on the instance-level, which allows you to
152
+ make the validation conditional:
153
+
176
154
  ```rb
177
155
  class ImageUploader < Shrine
178
156
  plugin :validation_helpers
179
157
 
180
158
  Attacher.validate do
181
- validate_extension_inclusion %w[jpg jpeg png gif]
182
- validate_mime_type_inclusion %w[image/jpeg image/png image/gif]
183
- validate_max_size 10*1024*1024 unless record.admin?
159
+ validate_max_size 10*1024*1024
160
+ validate_extension %w[jpg jpeg png webp]
161
+
162
+ if validate_mime_type %w[image/jpeg image/png image/webp]
163
+ validate_max_dimensions [5000, 5000]
164
+ end
184
165
  end
185
166
  end
186
167
  ```
187
168
 
188
169
  Refile extracts the MIME type from the file extension, which means it can
189
170
  easily be spoofed (just give a PHP file a `.jpg` extension). Shrine has the
190
- determine_mime_type plugin for determining MIME type from file *content*.
191
-
192
- ### Multiple uploads
193
-
194
- Shrine doesn't have a built-in solution for accepting multiple uploads, but
195
- it's actually very easy to do manually, see the [demo app] on how you can do
196
- multiple uploads directly to S3.
171
+ [`determine_mime_type`][determine_mime_type] plugin for determining MIME type
172
+ from file *content*.
197
173
 
198
- ## Direct uploads
174
+ ### Direct uploads
199
175
 
200
176
  Shrine borrows Refile's idea of direct uploads, and ships with
201
177
  `upload_endpoint` and `presign_endpoint` plugins which provide endpoints for
@@ -209,44 +185,68 @@ Shrine.plugin :upload_endpoint
209
185
  Shrine.presign_endpoint(:cache) # Rack app that generates presigns for specified storage
210
186
  ```
211
187
 
212
- Unlike Refile, Shrine doesn't ship with complete JavaScript which you can just
213
- include to make it work. However, [Uppy] is an excellent JavaScript file upload
214
- library that integrates wonderfully with Shrine, see the [demo app] for a
215
- complete example.
188
+ While Refile ships with a plug-and-play JavaScript for direct uploads, Shrine
189
+ instead adopts [Uppy], a modern and modular JavaScript file upload library that
190
+ happens to integrate well with Shrine.
191
+
192
+ ### Multiple uploads
193
+
194
+ Shrine doesn't have support for multiple uploads out-of-the-box like Refile
195
+ does. Instead, you can implement them using a separate table with a one-to-many
196
+ relationship to which the files will be attached. The [Multiple Files] guide
197
+ explains this setup in more detail.
216
198
 
217
199
  ## Migrating from Refile
218
200
 
219
201
  You have an existing app using Refile and you want to transfer it to
220
- Shrine. Let's assume we have a `Photo` model with the "image" attachment. First
221
- we need to create the `image_data` column for Shrine:
202
+ Shrine. Let's assume we have a `Photo` model with the "image" attachment.
203
+
204
+ ### 1. Add Shrine column
205
+
206
+ First we need to create the `image_data` column for Shrine:
222
207
 
223
208
  ```rb
224
209
  add_column :photos, :image_data, :text
225
210
  ```
226
211
 
212
+ ### 2. Dual write
213
+
227
214
  Afterwards we need to make new uploads write to the `image_data` column. This
228
215
  can be done by including the below module to all models that have Refile
229
216
  attachments:
230
217
 
231
218
  ```rb
219
+ require "shrine"
220
+
221
+ Shrine.storages = {
222
+ cache: ...,
223
+ store: ...,
224
+ }
225
+
226
+ Shrine.plugin :model
227
+
232
228
  module RefileShrineSynchronization
233
229
  def write_shrine_data(name)
234
- if read_attribute("#{name}_id").present?
235
- data = {
236
- storage: :store,
237
- id: send("#{name}_id"),
238
- metadata: {
239
- size: (send("#{name}_size") if respond_to?("#{name}_size")),
240
- filename: (send("#{name}_filename") if respond_to?("#{name}_filename")),
241
- mime_type: (send("#{name}_content_type") if respond_to?("#{name}_content_type")),
242
- }
243
- }
230
+ attacher = Shrine::Attacher.from_model(self, name)
244
231
 
245
- write_attribute(:"#{name}_data", data.to_json)
232
+ if read_attribute("#{name}_id").present?
233
+ attacher.set shrine_file(name)
246
234
  else
247
- write_attribute(:"#{name}_data", nil)
235
+ attacher.set nil
248
236
  end
249
237
  end
238
+
239
+ def shrine_file(name)
240
+ Shrine.uploaded_file(
241
+ storage: :store,
242
+ id: send("#{name}_id"),
243
+ metadata: {
244
+ "size" => (send("#{name}_size") if respond_to?("#{name}_size")),
245
+ "filename" => (send("#{name}_filename") if respond_to?("#{name}_filename")),
246
+ "mime_type" => (send("#{name}_content_type") if respond_to?("#{name}_content_type")),
247
+ }
248
+ )
249
+ end
250
250
  end
251
251
  ```
252
252
  ```rb
@@ -255,14 +255,18 @@ class Photo < ActiveRecord::Base
255
255
  include RefileShrineSynchronization
256
256
 
257
257
  before_save do
258
- write_shrine_data(:image) if changes.key?(:image_id)
258
+ write_shrine_data(:image) if image_id_changed?
259
259
  end
260
260
  end
261
261
  ```
262
262
 
263
263
  After you deploy this code, the `image_data` column should now be successfully
264
- synchronized with new attachments. Next step is to run a script which writes
265
- all existing Refile attachments to `image_data`:
264
+ synchronized with new attachments.
265
+
266
+ ### 3. Data migration
267
+
268
+ Next step is to run a script which writes all existing Refile attachments to
269
+ `image_data`:
266
270
 
267
271
  ```rb
268
272
  Photo.find_each do |photo|
@@ -271,9 +275,22 @@ Photo.find_each do |photo|
271
275
  end
272
276
  ```
273
277
 
278
+ ### 4. Rewrite code
279
+
274
280
  Now you should be able to rewrite your application so that it uses Shrine
275
- instead of Refile, using equivalent Shrine storages. For help with translating
276
- the code from Refile to Shrine, you can consult the reference below.
281
+ instead of Refile (you can consult the reference in the next section). You can
282
+ remove the `RefileShrineSynchronization` module as well.
283
+
284
+ ### 5. Remove Refile columns
285
+
286
+ If everything is looking good, we can remove Refile columns:
287
+
288
+ ```rb
289
+ remove_column :photos, :image_id
290
+ remove_column :photos, :image_size
291
+ remove_column :photos, :image_filename
292
+ remove_column :photos, :image_content_type
293
+ ```
277
294
 
278
295
  ## Refile to Shrine direct mapping
279
296
 
@@ -293,8 +310,8 @@ Shrine.storages = {
293
310
 
294
311
  #### `.app`, `.mount_point`, `.automount`
295
312
 
296
- The `upload_endpoint` and `presign_endpoint` plugins provide methods for
297
- generating Rack apps, but you need to mount them explicitly:
313
+ The Rack apps provided by the `*_endpoint` Shrine plugins are mounted
314
+ explicitly:
298
315
 
299
316
  ```rb
300
317
  # config/routes.rb
@@ -306,8 +323,8 @@ end
306
323
 
307
324
  #### `.allow_uploads_to`
308
325
 
309
- The `Shrine.upload_endpoint` and `Shrine.presign_endpoint` require you to
310
- specify the storage that will be used.
326
+ The `Shrine.upload_endpoint` and `Shrine.presign_endpoint` builders require you
327
+ to specify the storage that will be used.
311
328
 
312
329
  #### `.logger`
313
330
 
@@ -318,10 +335,10 @@ Shrine.logger
318
335
  #### `.processors`, `.processor`
319
336
 
320
337
  ```rb
321
- class MyUploader < Shrine
322
- plugin :processing
338
+ class ImageUploader < Shrine
339
+ plugin :derivatives
323
340
 
324
- process(:store) do |io, context|
341
+ derivation :thumbnail do |file, width, height|
325
342
  # ...
326
343
  end
327
344
  end
@@ -329,7 +346,7 @@ end
329
346
 
330
347
  #### `.types`
331
348
 
332
- In Shrine validations are done by calling `.validate` on the attacher class:
349
+ Shrine defines validations on the uploader class level:
333
350
 
334
351
  ```rb
335
352
  class MyUploader < Shrine
@@ -341,42 +358,45 @@ class MyUploader < Shrine
341
358
  end
342
359
  ```
343
360
 
344
- #### `.extract_filename`, `.extract_content_type`
361
+ #### `.extract_filename`
345
362
 
346
- In Shrine equivalents are (private) methods `Shrine#extract_filename` and
347
- `Shrine#extract_mime_type`.
363
+ Shrine's equivalent is a `Shrine#extract_filename` private method. You can
364
+ instead use the `Shrine#extract_metadata` public method.
348
365
 
349
- #### `.app_url`
366
+ #### `.extract_content_type`
350
367
 
351
- You should use your framework to generate the URL to your mounted direct
352
- endpoint.
368
+ The [`determine_mime_type`][determine_mime_type] plugin provides a
369
+ `Shrine.determine_mime_type` method.
353
370
 
354
- #### `.attachment_url`, `.file_url`
371
+ #### `.app_url`, `.upload_url`, `.attachment_upload_url`, `.presign_url`, `.attachment_presign_url`
355
372
 
356
- You can call `#url` on the uploaded file, or `#<name>_url` on the model.
357
- Additionally you can use the `download_endpoint` plugin.
373
+ Shrine requires you to use your framework to generate URLs to mounted
374
+ endpoints.
358
375
 
359
- #### `.upload_url`, `.attachment_upload_url`, `.presign_url`, `.attachment_presign_url`
376
+ #### `.attachment_url`, `.file_url`
360
377
 
361
- These should be generated directly by you, it depends on where you've mounted
362
- the direct endpoint.
378
+ You can call `#url` on the uploaded file, or `#<name>_url` on the model.
379
+ Alternatively, you can use `#download_url` provided by the `download_endpoint`
380
+ plugin.
363
381
 
364
382
  #### `.host`, `.cdn_host`, `.app_host`, `.allow_downloads_from`, `allow_origin`, `.content_max_age`
365
383
 
366
- Not needed since Shrine doesn't offer on-the-fly processing.
384
+ These can be configured on individual `*_endpoint` plugins.
367
385
 
368
386
  #### `.secret_key`, `.token`, `.valid_token?`
369
387
 
370
- Not needed since Shrine doesn't offer on-the-fly processing.
388
+ The secret key is required for the
389
+ [`derivation_endpoint`][derivation_endpoint], but these methods are not
390
+ exposed.
371
391
 
372
- ### `attachment`
392
+ ### `Attachment`
373
393
 
374
394
  Shrine's equivalent to calling the attachment is including an attachment module
375
395
  of an uploader:
376
396
 
377
397
  ```rb
378
- class User
379
- include ImageUploader::Attachment.new(:avatar)
398
+ class Photo
399
+ include ImageUploader::Attachment(:image)
380
400
  end
381
401
  ```
382
402
 
@@ -390,8 +410,8 @@ class ImageUploader < Shrine
390
410
  plugin :validation_helpers
391
411
 
392
412
  Attacher.validate do
393
- validate_extension_inclusion %w[jpg jpeg png]
394
- validate_mime_type_inclusion %w[image/jpeg image/png]
413
+ validate_extension %w[jpg jpeg png]
414
+ validate_mime_type %w[image/jpeg image/png]
395
415
  end
396
416
  end
397
417
  ```
@@ -417,7 +437,7 @@ No equivalent currently exists in Shrine.
417
437
 
418
438
  ### `accepts_attachments_for`
419
439
 
420
- No equivalent in Shrine, but take a look at the "[Multiple Files]" guide.
440
+ No equivalent in Shrine, but take a look at the [Multiple Files] guide.
421
441
 
422
442
  ### Form helpers
423
443
 
@@ -438,7 +458,7 @@ Shrine.plugin :cached_attachment_data
438
458
  ```
439
459
  ```rb
440
460
  form_for @user do |form|
441
- form.hidden_field :profile_image, value: @user.cached_profile_image_data
461
+ form.hidden_field :profile_image, value: @user.cached_profile_image_data, id: nil
442
462
  form.file_field :profile_image
443
463
  end
444
464
  ```
@@ -455,7 +475,7 @@ Shrine.plugin :remove_attachment
455
475
  ```
456
476
  ```rb
457
477
  form_for @user do |form|
458
- form.hidden_field :profile_image, value: @user.cached_profile_image_data
478
+ form.hidden_field :profile_image, value: @user.cached_profile_image_data, id: nil
459
479
  form.file_field :profile_image
460
480
  form.check_box :remove_profile_image
461
481
  end
@@ -471,18 +491,16 @@ Shrine.plugin :remote_url
471
491
  ```
472
492
  ```rb
473
493
  form_for @user do |form|
474
- form.hidden_field :profile_image, value: @user.cached_profile_image_data
494
+ form.hidden_field :profile_image, value: @user.cached_profile_image_data, id: nil
475
495
  form.file_field :profile_image
476
496
  form.text_field :profile_image_remote_url
477
497
  end
478
498
  ```
479
499
 
480
- [shrine-cloudinary]: https://github.com/shrinerb/shrine-cloudinary
481
- [shrine-imgix]: https://github.com/shrinerb/shrine-imgix
482
- [shrine-uploadcare]: https://github.com/shrinerb/shrine-uploadcare
483
- [Attache]: https://github.com/choonkeat/attache
484
- [image_processing]: https://github.com/janko/image_processing
485
500
  [Uppy]: https://uppy.io
486
- [Direct Uploads to S3]: /doc/direct_s3.md#readme
487
- [demo app]: https://github.com/shrinerb/shrine/tree/master/demo
488
- [Multiple Files]: /doc/multiple_files.md#readme
501
+ [derivation_endpoint]: https://shrinerb.com/docs/plugins/derivation_endpoint
502
+ [download_endpoint]: https://shrinerb.com/docs/plugins/download_endpoint
503
+ [derivatives]: https://shrinerb.com/docs/plugins/derivatives
504
+ [metadata_attributes]: https://shrinerb.com/docs/plugins/metadata_attributes
505
+ [determine_mime_type]: https://shrinerb.com/docs/plugins/determine_mime_type
506
+ [Multiple Files]: https://shrinerb.com/docs/multiple-files
@@ -1,3 +1,7 @@
1
+ ---
2
+ title: Shrine 1.0.0
3
+ ---
4
+
1
5
  # Backwards compatibility
2
6
 
3
7
  * The `delete_invalid` plugin was removed, because it was unstable since next
@@ -1,3 +1,7 @@
1
+ ---
2
+ title: Shrine 1.1.0
3
+ ---
4
+
1
5
  # New plugins
2
6
 
3
7
  * The `download_endpoint` plugin has been added, which allows downloading files
@@ -39,11 +43,11 @@ plugin :keep_location, :cache => :store
39
43
  ```rb
40
44
  user = User.new
41
45
  user.avatar = image
42
- user.avatar.storage_key #=> "cache"
46
+ user.avatar.storage_key #=> :cache
43
47
  user.avatar.id #=> "abc123.jpg"
44
48
 
45
49
  user.save
46
- user.avatar.storage_key #=> "store"
50
+ user.avatar.storage_key #=> :store
47
51
  user.avatar.id #=> "abc123.jpg"
48
52
  ```
49
53
 
@@ -1,3 +1,7 @@
1
+ ---
2
+ title: Shrine 1.2.0
3
+ ---
4
+
1
5
  New features
2
6
  ============
3
7
 
@@ -1,3 +1,7 @@
1
+ ---
2
+ title: Shrine 1.3.0
3
+ ---
4
+
1
5
  New features
2
6
  ============
3
7
 
@@ -1,3 +1,7 @@
1
+ ---
2
+ title: Shrine 1.4.0
3
+ ---
4
+
1
5
  New features
2
6
  ============
3
7
 
@@ -1,3 +1,7 @@
1
+ ---
2
+ title: Shrine 1.4.1
3
+ ---
4
+
1
5
  Regressions
2
6
  ===========
3
7
 
@@ -1,3 +1,7 @@
1
+ ---
2
+ title: Shrine 1.4.2
3
+ ---
4
+
1
5
  Regressions
2
6
  ===========
3
7
 
@@ -1,3 +1,7 @@
1
+ ---
2
+ title: Shrine 2.0.0
3
+ ---
4
+
1
5
  Backwards compatibility
2
6
  =======================
3
7
 
@@ -1,3 +1,7 @@
1
+ ---
2
+ title: Shrine 2.0.1
3
+ ---
4
+
1
5
  Regressions
2
6
  ===========
3
7