shrine 2.14.0 → 2.15.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of shrine might be problematic. Click here for more details.

Files changed (149) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +384 -374
  3. data/README.md +132 -63
  4. data/doc/advantages.md +191 -109
  5. data/doc/attacher.md +1 -1
  6. data/doc/carrierwave.md +4 -4
  7. data/doc/creating_storages.md +2 -2
  8. data/doc/design.md +2 -2
  9. data/doc/direct_s3.md +3 -3
  10. data/doc/metadata.md +1 -1
  11. data/doc/multiple_files.md +2 -2
  12. data/doc/paperclip.md +3 -3
  13. data/doc/plugins/activerecord.md +92 -0
  14. data/doc/plugins/add_metadata.md +93 -0
  15. data/doc/plugins/backgrounding.md +148 -0
  16. data/doc/plugins/backup.md +29 -0
  17. data/doc/plugins/cached_attachment_data.md +23 -0
  18. data/doc/plugins/copy.md +22 -0
  19. data/doc/plugins/data_uri.md +92 -0
  20. data/doc/plugins/default_storage.md +16 -0
  21. data/doc/plugins/default_url.md +33 -0
  22. data/doc/plugins/default_url_options.md +22 -0
  23. data/doc/plugins/delete_promoted.md +10 -0
  24. data/doc/plugins/delete_raw.md +16 -0
  25. data/doc/plugins/derivation_endpoint.md +747 -0
  26. data/doc/plugins/determine_mime_type.md +64 -0
  27. data/doc/plugins/direct_upload.md +170 -0
  28. data/doc/plugins/download_endpoint.md +83 -0
  29. data/doc/plugins/dynamic_storage.md +20 -0
  30. data/doc/plugins/hooks.md +56 -0
  31. data/doc/plugins/included.md +15 -0
  32. data/doc/plugins/infer_extension.md +57 -0
  33. data/doc/plugins/keep_files.md +20 -0
  34. data/doc/plugins/logging.md +39 -0
  35. data/doc/plugins/metadata_attribues.md +43 -0
  36. data/doc/plugins/migration_helpers.md +58 -0
  37. data/doc/plugins/module_include.md +40 -0
  38. data/doc/plugins/moving.md +17 -0
  39. data/doc/plugins/multi_delete.md +18 -0
  40. data/doc/plugins/parallelize.md +14 -0
  41. data/doc/plugins/parsed_json.md +9 -0
  42. data/doc/plugins/presign_endpoint.md +133 -0
  43. data/doc/plugins/pretty_location.md +29 -0
  44. data/doc/plugins/processing.md +68 -0
  45. data/doc/plugins/rack_file.md +49 -0
  46. data/doc/plugins/rack_response.md +96 -0
  47. data/doc/plugins/recache.md +27 -0
  48. data/doc/plugins/refresh_metadata.md +31 -0
  49. data/doc/plugins/remote_url.md +104 -0
  50. data/doc/plugins/remove_attachment.md +16 -0
  51. data/doc/plugins/remove_invalid.md +9 -0
  52. data/doc/plugins/restore_cached_data.md +14 -0
  53. data/doc/plugins/sequel.md +64 -0
  54. data/doc/plugins/signature.md +49 -0
  55. data/doc/plugins/store_dimensions.md +68 -0
  56. data/doc/plugins/tempfile.md +40 -0
  57. data/doc/plugins/upload_endpoint.md +123 -0
  58. data/doc/plugins/upload_options.md +28 -0
  59. data/doc/plugins/validation_helpers.md +129 -0
  60. data/doc/plugins/versions.md +179 -0
  61. data/doc/processing.md +217 -247
  62. data/doc/refile.md +3 -3
  63. data/doc/release_notes/1.0.0.md +143 -0
  64. data/doc/release_notes/1.1.0.md +184 -0
  65. data/doc/release_notes/1.2.0.md +37 -0
  66. data/doc/release_notes/1.3.0.md +90 -0
  67. data/doc/release_notes/1.4.0.md +167 -0
  68. data/doc/release_notes/1.4.1.md +9 -0
  69. data/doc/release_notes/1.4.2.md +20 -0
  70. data/doc/release_notes/2.0.0.md +173 -0
  71. data/doc/release_notes/2.0.1.md +12 -0
  72. data/doc/release_notes/2.1.0.md +59 -0
  73. data/doc/release_notes/2.1.1.md +8 -0
  74. data/doc/release_notes/2.10.0.md +52 -0
  75. data/doc/release_notes/2.10.1.md +6 -0
  76. data/doc/release_notes/2.11.0.md +69 -0
  77. data/doc/release_notes/2.12.0.md +65 -0
  78. data/doc/release_notes/2.13.0.md +146 -0
  79. data/doc/release_notes/2.14.0.md +278 -0
  80. data/doc/release_notes/2.15.0.md +82 -0
  81. data/doc/release_notes/2.2.0.md +98 -0
  82. data/doc/release_notes/2.3.0.md +50 -0
  83. data/doc/release_notes/2.3.1.md +10 -0
  84. data/doc/release_notes/2.4.0.md +87 -0
  85. data/doc/release_notes/2.4.1.md +29 -0
  86. data/doc/release_notes/2.5.0.md +130 -0
  87. data/doc/release_notes/2.6.0.md +254 -0
  88. data/doc/release_notes/2.6.1.md +14 -0
  89. data/doc/release_notes/2.7.0.md +180 -0
  90. data/doc/release_notes/2.8.0.md +95 -0
  91. data/doc/release_notes/2.9.0.md +82 -0
  92. data/doc/retrieving_uploads.md +1 -1
  93. data/doc/storage/file_system.md +96 -0
  94. data/doc/storage/s3.md +293 -0
  95. data/doc/validation.md +1 -1
  96. data/lib/shrine/plugins/_urlsafe_serialization.rb +33 -125
  97. data/lib/shrine/plugins/activerecord.rb +0 -78
  98. data/lib/shrine/plugins/add_metadata.rb +0 -80
  99. data/lib/shrine/plugins/backgrounding.rb +0 -134
  100. data/lib/shrine/plugins/backup.rb +0 -22
  101. data/lib/shrine/plugins/cached_attachment_data.rb +0 -15
  102. data/lib/shrine/plugins/copy.rb +0 -14
  103. data/lib/shrine/plugins/data_uri.rb +0 -73
  104. data/lib/shrine/plugins/default_storage.rb +0 -11
  105. data/lib/shrine/plugins/default_url.rb +0 -25
  106. data/lib/shrine/plugins/default_url_options.rb +0 -16
  107. data/lib/shrine/plugins/delete_promoted.rb +0 -6
  108. data/lib/shrine/plugins/delete_raw.rb +0 -10
  109. data/lib/shrine/plugins/derivation_endpoint.rb +652 -0
  110. data/lib/shrine/plugins/determine_mime_type.rb +1 -85
  111. data/lib/shrine/plugins/direct_upload.rb +0 -155
  112. data/lib/shrine/plugins/download_endpoint.rb +11 -73
  113. data/lib/shrine/plugins/dynamic_storage.rb +0 -17
  114. data/lib/shrine/plugins/hooks.rb +0 -48
  115. data/lib/shrine/plugins/included.rb +0 -12
  116. data/lib/shrine/plugins/infer_extension.rb +0 -49
  117. data/lib/shrine/plugins/keep_files.rb +0 -19
  118. data/lib/shrine/plugins/logging.rb +0 -39
  119. data/lib/shrine/plugins/metadata_attributes.rb +0 -35
  120. data/lib/shrine/plugins/migration_helpers.rb +0 -50
  121. data/lib/shrine/plugins/module_include.rb +0 -32
  122. data/lib/shrine/plugins/moving.rb +0 -12
  123. data/lib/shrine/plugins/multi_delete.rb +0 -13
  124. data/lib/shrine/plugins/parallelize.rb +0 -8
  125. data/lib/shrine/plugins/parsed_json.rb +0 -5
  126. data/lib/shrine/plugins/presign_endpoint.rb +2 -117
  127. data/lib/shrine/plugins/pretty_location.rb +0 -22
  128. data/lib/shrine/plugins/processing.rb +0 -55
  129. data/lib/shrine/plugins/rack_file.rb +0 -39
  130. data/lib/shrine/plugins/rack_response.rb +0 -81
  131. data/lib/shrine/plugins/recache.rb +0 -21
  132. data/lib/shrine/plugins/refresh_metadata.rb +0 -24
  133. data/lib/shrine/plugins/remote_url.rb +0 -85
  134. data/lib/shrine/plugins/remove_attachment.rb +0 -10
  135. data/lib/shrine/plugins/remove_invalid.rb +0 -6
  136. data/lib/shrine/plugins/restore_cached_data.rb +0 -10
  137. data/lib/shrine/plugins/sequel.rb +0 -54
  138. data/lib/shrine/plugins/signature.rb +0 -37
  139. data/lib/shrine/plugins/store_dimensions.rb +0 -63
  140. data/lib/shrine/plugins/tempfile.rb +4 -35
  141. data/lib/shrine/plugins/upload_endpoint.rb +2 -109
  142. data/lib/shrine/plugins/upload_options.rb +0 -20
  143. data/lib/shrine/plugins/validation_helpers.rb +0 -36
  144. data/lib/shrine/plugins/versions.rb +0 -156
  145. data/lib/shrine/storage/file_system.rb +0 -77
  146. data/lib/shrine/storage/s3.rb +0 -249
  147. data/lib/shrine/version.rb +1 -1
  148. data/shrine.gemspec +2 -2
  149. metadata +86 -6
@@ -0,0 +1,20 @@
1
+ # Keep Files
2
+
3
+ The `keep_files` plugin gives you the ability to prevent files from being
4
+ deleted. This functionality is useful when implementing soft deletes, or when
5
+ implementing some kind of [event store] where you need to track history.
6
+
7
+ The plugin accepts the following options:
8
+
9
+ | Option | Description |
10
+ | :------ | :---------- |
11
+ | `:destroyed` | If set to `true`, destroying the record won't delete the associated attachment. |
12
+ | `:replaced` | If set to `true`, uploading a new attachment won't delete the old one. |
13
+
14
+ For example, the following will keep destroyed and replaced files:
15
+
16
+ ```rb
17
+ plugin :keep_files, destroyed: true, replaced: true
18
+ ```
19
+
20
+ [event store]: http://docs.geteventstore.com/introduction/event-sourcing-basics/
@@ -0,0 +1,39 @@
1
+ # Logging
2
+
3
+ The `logging` plugin logs any storing/processing/deleting that is performed.
4
+
5
+ ```rb
6
+ plugin :logging
7
+ ```
8
+
9
+ This plugin is useful when you want to have overview of what exactly is going
10
+ on, or you simply want to have it logged for future debugging. By default the
11
+ logging output looks something like this:
12
+
13
+ ```
14
+ 2015-10-09T20:06:06.676Z #25602: STORE[cache] ImageUploader[:avatar] User[29543] 1 file (0.1s)
15
+ 2015-10-09T20:06:06.854Z #25602: PROCESS[store]: ImageUploader[:avatar] User[29543] 1-3 files (0.22s)
16
+ 2015-10-09T20:06:07.133Z #25602: DELETE[destroyed]: ImageUploader[:avatar] User[29543] 3 files (0.07s)
17
+ ```
18
+
19
+ The plugin accepts the following options:
20
+
21
+ | Option | Description |
22
+ | :-------- | :---------- |
23
+ | `:format` | This allows you to change the logging output into something that may be easier to grep. Accepts `:human` (default), `:json` and `:logfmt`. |
24
+ | `:stream` | The default logging stream is `$stdout`, but you may want to change it, e.g. if you log into a file. This option is passed directly to `Logger.new` (from the "logger" Ruby standard library). |
25
+ | `:logger` | This allows you to change the logger entirely. This is useful for example in Rails applications, where you might want to assign this option to `Rails.logger`. |
26
+
27
+ The default format is probably easiest to read, but may not be easiest to grep.
28
+ If this is important to you, you can switch to another format:
29
+
30
+ ```rb
31
+ plugin :logging, format: :json
32
+ # {"action":"upload","phase":"cache","uploader":"ImageUploader","attachment":"avatar",...}
33
+
34
+ plugin :logging, format: :logfmt
35
+ # action=upload phase=cache uploader=ImageUploader attachment=avatar record_class=User ...
36
+ ```
37
+
38
+ Logging is by default disabled in tests, but you can enable it by setting
39
+ `Shrine.logger.level = Logger::INFO`.
@@ -0,0 +1,43 @@
1
+ # Metadata Attributes
2
+
3
+ The `metadata_attributes` plugin allows you to sync attachment metadata to
4
+ additional record attributes. You can provide a hash of mappings to the plugin
5
+ call itself or the `Attacher.metadata_attributes` method:
6
+
7
+ ```rb
8
+ plugin :metadata_attributes, :size => :size, :mime_type => :type
9
+ # or
10
+ plugin :metadata_attributes
11
+ Attacher.metadata_attributes :size => :size, :mime_type => :type
12
+ ```
13
+
14
+ The above configuration will sync `size` metadata field to `<attachment>_size`
15
+ record attribute, and `mime_type` metadata field to `<attachment>_type` record
16
+ attribute.
17
+
18
+ ```rb
19
+ user.avatar = image
20
+ user.avatar.metadata["size"] #=> 95724
21
+ user.avatar_size #=> 95724
22
+ user.avatar.metadata["mime_type"] #=> "image/jpeg"
23
+ user.avatar_type #=> "image/jpeg"
24
+
25
+ user.avatar = nil
26
+ user.avatar_size #=> nil
27
+ user.avatar_type #=> nil
28
+ ```
29
+
30
+ If you want to specify the full record attribute name, pass the record
31
+ attribute name as a string instead of a symbol.
32
+
33
+ ```rb
34
+ Attacher.metadata_attributes :filename => "original_filename"
35
+
36
+ # ...
37
+
38
+ photo.image = image
39
+ photo.original_filename #=> "nature.jpg"
40
+ ```
41
+
42
+ If any corresponding metadata attribute doesn't exist on the record, that
43
+ metadata sync will be silently skipped.
@@ -0,0 +1,58 @@
1
+ # Migration Helpers
2
+
3
+ The migration_helpers plugin gives the attacher additional helper methods which
4
+ are convenient when doing file migrations.
5
+
6
+ The plugin also allows convenient delegating to these methods through the
7
+ model, by setting `:delegate`:
8
+
9
+ ```rb
10
+ plugin :migration_helpers, delegate: true
11
+ ```
12
+
13
+ ## `update_stored`
14
+
15
+ This method updates the record's attachment with the result of the given block.
16
+
17
+ ```rb
18
+ user.avatar_attacher.update_stored do |avatar|
19
+ user.avatar_attacher.store.upload(avatar) # saved to the record
20
+ end
21
+
22
+ # with model delegation
23
+ user.update_avatar do |avatar|
24
+ user.avatar_store.upload(avatar) # saved to the record
25
+ end
26
+ ```
27
+
28
+ The block will get triggered _only_ if the attachment is present and not
29
+ cached, *and* will save the record only if the record's attachment hasn't
30
+ changed in the time it took to execute the block. This method is most useful
31
+ for adding/removing versions and changing locations of files.
32
+
33
+ ## `cached?` and `stored?`
34
+
35
+ These methods return true if attachment exists and is cached/stored:
36
+
37
+ ```rb
38
+ user.avatar_attacher.cached? # user.avatar && user.avatar_attacher.cache.uploaded?(user.avatar)
39
+ user.avatar_attacher.stored? # user.avatar && user.avatar_attacher.store.uploaded?(user.avatar)
40
+
41
+ # with model delegation
42
+ user.avatar_cached?
43
+ user.avatar_stored?
44
+ ```
45
+
46
+ ## `attachment_cache` and `attachment_store`
47
+
48
+ These methods return cache and store uploaders used by the underlying attacher:
49
+
50
+ ```rb
51
+ # these methods already exist without migration_helpers
52
+ user.avatar_attacher.cache #=> #<Shrine @storage_key=:cache @storage=#<Shrine::Storage::FileSystem @directory=public/uploads>>
53
+ user.avatar_attacher.store #=> #<Shrine @storage_key=:store @storage=#<Shrine::Storage::S3:0x007fb8343397c8 @bucket=#<Aws::S3::Bucket name="foo">>>
54
+
55
+ # with model delegation
56
+ user.avatar_cache
57
+ user.avatar_store
58
+ ```
@@ -0,0 +1,40 @@
1
+ # Module Include
2
+
3
+ The `module_include` plugin allows you to extend Shrine's core classes for the
4
+ given uploader with modules/methods.
5
+
6
+ ```rb
7
+ plugin :module_include
8
+ ```
9
+
10
+ To add a module to a core class, call the appropriate method:
11
+
12
+ ```rb
13
+ attachment_module CustomAttachmentMethods
14
+ attacher_module CustomAttacherMethods
15
+ file_module CustomFileMethods
16
+ ```
17
+
18
+ Alternatively you can pass in a block (which internally creates a module):
19
+
20
+ ```rb
21
+ attachment_module do
22
+ def included(model)
23
+ super
24
+
25
+ name = attachment_name
26
+
27
+ define_method :"#{name}_size" do |version|
28
+ attachment = send(name)
29
+ if attachment.is_a?(Hash)
30
+ attachment[version].size
31
+ elsif attachment
32
+ attachment.size
33
+ end
34
+ end
35
+ end
36
+ end
37
+ ```
38
+
39
+ The above defines an additional `#<attachment>_size` method on the attachment
40
+ module, which is what is included in your model.
@@ -0,0 +1,17 @@
1
+ # Moving
2
+
3
+ The `moving` plugin will *move* files to storages instead of copying them, when
4
+ the storage supports it. For FileSystem this will issue a `mv` command, which
5
+ is instantaneous regardless of the filesize, so in that case loading this
6
+ plugin can significantly speed up the attachment process.
7
+
8
+ ```rb
9
+ plugin :moving
10
+ ```
11
+
12
+ By default files will be moved whenever the storage supports it. If you want
13
+ moving to happen only for certain storages, you can set `:storages`:
14
+
15
+ ```rb
16
+ plugin :moving, storages: [:cache]
17
+ ```
@@ -0,0 +1,18 @@
1
+ # Multi Delete
2
+
3
+ The `multi_delete` plugins allows you to leverage your storage's multi delete
4
+ capabilities.
5
+
6
+ ```rb
7
+ plugin :multi_delete
8
+ ```
9
+
10
+ This plugin allows you pass an array of files to `Shrine#delete`.
11
+
12
+ ```rb
13
+ uploader.delete([file1, file2, file3])
14
+ ```
15
+
16
+ Now if you're using Storage::S3, deleting an array of files will issue a single
17
+ HTTP request. Some other storages may support multi deletes as well. The
18
+ `versions` plugin uses this plugin for deleting multiple versions at once.
@@ -0,0 +1,14 @@
1
+ # Parallelize
2
+
3
+ The `parallelize` plugin parallelizes uploads and deletes of multiple versions
4
+ using threads.
5
+
6
+ ```rb
7
+ plugin :parallelize
8
+ ```
9
+
10
+ By default a pool of 3 threads will be used, but you can change that:
11
+
12
+ ```rb
13
+ plugin :parallelize, threads: 5
14
+ ```
@@ -0,0 +1,9 @@
1
+ # Parsed JSON
2
+
3
+ The `parsed_json` plugin is suitable for the case when your framework is
4
+ automatically parsing JSON query parameters, allowing you to assign cached
5
+ files with hashes/arrays.
6
+
7
+ ```rb
8
+ plugin :parsed_json
9
+ ```
@@ -0,0 +1,133 @@
1
+ # Presign Endpoint
2
+
3
+ The `presign_endpoint` plugin provides a Rack endpoint which generates the URL,
4
+ fields, and headers that can be used to upload files directly to a storage
5
+ service. On the client side it's recommended to use [Uppy] for asynchronous
6
+ uploads. Storage services that support direct uploads include [Amazon S3],
7
+ [Google Cloud Storage], [Microsoft Azure Storage] and more.
8
+
9
+ ```rb
10
+ plugin :presign_endpoint
11
+ ```
12
+
13
+ The plugin adds a `Shrine.presign_endpoint` method which, given a storage
14
+ identifier, returns a Rack application that accepts GET requests and generates
15
+ a presign for the specified storage. You can run this Rack application inside
16
+ your app:
17
+
18
+ ```rb
19
+ # config.ru (Rack)
20
+ map "/images/presign" do
21
+ run ImageUploader.presign_endpoint(:cache)
22
+ end
23
+
24
+ # OR
25
+
26
+ # config/routes.rb (Rails)
27
+ Rails.application.routes.draw do
28
+ mount ImageUploader.presign_endpoint(:cache) => "/images/presign"
29
+ end
30
+ ```
31
+
32
+ Asynchronous upload is typically meant to replace the caching phase in the
33
+ default synchronous workflow, so we want to generate parameters for uploads to
34
+ the temporary (`:cache`) storage.
35
+
36
+ The above will create a `GET /images/presign` endpoint, which calls `#presign`
37
+ on the storage and returns the HTTP verb, URL, params, and headers needed for a
38
+ single upload directly to the storage service, in JSON format.
39
+
40
+ ```rb
41
+ # GET /images/presign
42
+ {
43
+ "method": "post",
44
+ "url": "https://my-bucket.s3-eu-west-1.amazonaws.com",
45
+ "fields": {
46
+ "key": "b7d575850ba61b44c8a9ff889dfdb14d88cdc25f8dd121004c8",
47
+ "policy": "eyJleHBpcmF0aW9uIjoiMjAxNS0QwMToxMToyOVoiLCJjb25kaXRpb25zIjpbeyJidWNrZXQiOiJ...",
48
+ "x-amz-credential": "AKIAIJF55TMZYT6Q/20151024/eu-west-1/s3/aws4_request",
49
+ "x-amz-algorithm": "AWS4-HMAC-SHA256",
50
+ "x-amz-date": "20151024T001129Z",
51
+ "x-amz-signature": "c1eb634f83f96b69bd675f535b3ff15ae184b102fcba51e4db5f4959b4ae26f4"
52
+ },
53
+ "headers": {}
54
+ }
55
+ ```
56
+
57
+ ## Location
58
+
59
+ By default the generated location won't have any file extension, but you can
60
+ specify one by sending the `filename` query parameter:
61
+
62
+ ```
63
+ GET /images/presign?filename=nature.jpg
64
+ ```
65
+
66
+ It's also possible to customize how the presign location is generated:
67
+
68
+ ```rb
69
+ plugin :presign_endpoint, presign_location: -> (request) do
70
+ "#{SecureRandom.hex}/#{request.params["filename"]}"
71
+ end
72
+ ```
73
+
74
+ ## Options
75
+
76
+ Some storages accept additional presign options, which you can pass in via
77
+ `:presign_options`, here is an example for S3 storage:
78
+
79
+ ```rb
80
+ plugin :presign_endpoint, presign_options: -> (request) do
81
+ # Uppy will send the "filename" and "type" query parameters
82
+ filename = request.params["filename"]
83
+ type = request.params["type"]
84
+
85
+ {
86
+ content_length_range: 0..(10*1024*1024), # limit filesize to 10MB
87
+ content_disposition: ContentDisposition.inline(filename), # download with original filename
88
+ content_type: type, # set correct content type
89
+ }
90
+ end
91
+ ```
92
+
93
+ The example above uses the [content_disposition] gem to correctly format the
94
+ `Content-Disposition` header value.
95
+
96
+ The `:presign_options` can be a Proc or a Hash.
97
+
98
+ ## Presign
99
+
100
+ You can also customize how the presign itself is generated via the `:presign`
101
+ option:
102
+
103
+ ```rb
104
+ plugin :presign_endpoint, presign: -> (id, options, request) do
105
+ # return a Hash with :url, :fields, and :headers keys
106
+ end
107
+ ```
108
+
109
+ ## Response
110
+
111
+ The response returned by the endpoint can be customized via the
112
+ `:rack_response` option:
113
+
114
+ ```rb
115
+ plugin :presign_endpoint, rack_response: -> (data, request) do
116
+ body = { endpoint: data[:url], params: data[:fields], headers: data[:headers] }.to_json
117
+ [201, { "Content-Type" => "application/json" }, [body]]
118
+ end
119
+ ```
120
+
121
+ ## Ad-hoc options
122
+
123
+ You can override any of the options above when creating the endpoint:
124
+
125
+ ```rb
126
+ Shrine.presign_endpoint(:cache, presign_location: "${filename}")
127
+ ```
128
+
129
+ [Uppy]: https://uppy.io
130
+ [Amazon S3]: https://aws.amazon.com/s3/
131
+ [Google Cloud Storage]: https://cloud.google.com/storage/
132
+ [Microsoft Azure Storage]: https://azure.microsoft.com/en-us/services/storage/
133
+ [content_disposition]: https://github.com/shrinerb/content_disposition
@@ -0,0 +1,29 @@
1
+ # Pretty Location
2
+
3
+ The `pretty_location` plugin attempts to generate a nicer folder structure for
4
+ uploaded files.
5
+
6
+ ```rb
7
+ plugin :pretty_location
8
+ ```
9
+
10
+ This plugin uses the context information from the Attacher to try to generate a
11
+ nested folder structure which separates files for each record. The newly
12
+ generated locations will typically look like this:
13
+
14
+ ```rb
15
+ "user/564/avatar/thumb-493g82jf23.jpg"
16
+ # :model/:id/:attachment/:version-:uid.:extension
17
+ ```
18
+
19
+ By default if a record class is inside a namespace, only the "inner" class name
20
+ is used in the location. If you want to include the namespace, you can pass in
21
+ the `:namespace` option with the desired separator as the value:
22
+
23
+ ```rb
24
+ plugin :pretty_location, namespace: "_"
25
+ # "blog_user/.../493g82jf23.jpg"
26
+
27
+ plugin :pretty_location, namespace: "/"
28
+ # "blog/user/.../493g82jf23.jpg"
29
+ ```
@@ -0,0 +1,68 @@
1
+ # Processing
2
+
3
+ Shrine uploaders can define the `#process` method, which will get called
4
+ whenever a file is uploaded. It is given the original file, and is expected to
5
+ return the processed files.
6
+
7
+ ```rb
8
+ def process(io, context)
9
+ # you can process the original file `io` and return processed file(s)
10
+ end
11
+ ```
12
+
13
+ However, when handling files as attachments, the same file is uploaded to
14
+ temporary and permanent storage. Since we only want to apply the same
15
+ processing once, we need to branch based on the context.
16
+
17
+ ```rb
18
+ def process(io, context)
19
+ if context[:action] == :store # promote phase
20
+ # ...
21
+ end
22
+ end
23
+ ```
24
+
25
+ The `processing` plugin simplifies this by allowing us to declaratively define
26
+ file processing for specified actions.
27
+
28
+ ```rb
29
+ plugin :processing
30
+
31
+ process(:store) do |io, context|
32
+ # ...
33
+ end
34
+ ```
35
+
36
+ An example of resizing an image using the [image_processing] library:
37
+
38
+ ```rb
39
+ require "image_processing/mini_magick"
40
+
41
+ process(:store) do |io, context|
42
+ io.download do |original|
43
+ ImageProcessing::MiniMagick
44
+ .source(original)
45
+ .resize_to_limit!(800, 800)
46
+ end
47
+ end
48
+ ```
49
+
50
+ The declarations are additive and inheritable, so for the same action you can
51
+ declare multiple blocks, and they will be performed in the same order, with
52
+ output from previous block being the input to next.
53
+
54
+ ## Manually Run Processing
55
+
56
+ You can manually trigger the defined processing via the uploader by calling
57
+ `#upload` or `#process` and setting `:action` to the name of your processing
58
+ block:
59
+
60
+ ```rb
61
+ uploader.upload(file, action: :store) # process and upload
62
+ uploader.process(file, action: :store) # only process
63
+ ```
64
+
65
+ If you want the result of processing to be multiple files, use the `versions`
66
+ plugin.
67
+
68
+ [image_processing]: https://github.com/janko/image_processing