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
@@ -145,4 +145,4 @@ class ImageUploader < ApplicationUploader
145
145
  end
146
146
  ```
147
147
 
148
- [ImageProcessing]: https://github.com/janko-m/image_processing
148
+ [ImageProcessing]: https://github.com/janko/image_processing
@@ -2,116 +2,66 @@
2
2
 
3
3
  require "base64"
4
4
  require "json"
5
- require "openssl"
6
5
 
7
6
  class Shrine
8
7
  module Plugins
9
- # The `urlsafe_serialization` plugin provides the ability to serialize and
10
- # deserialize a `Shrine::UploadedFile` in a way that's suitable for
11
- # including in a URL.
12
- #
13
- # plugin :urlsafe_serialization
14
- #
15
- # The plugin defines `urlsafe_dump` and `urlsafe_load` methods on
16
- # `Shrine::UploadedFile`. The file is first serialized to JSON, then
17
- # encoded with base64.
18
- #
19
- # serialized = uploaded_file.urlsafe_dump
20
- # # or
21
- # serialized = MyUploader::UploadedFile.urlsafe_dump(uploaded_file)
22
- # serialized #=> "eyJpZCI6IjlhZGM0NmIzZjI..."
23
- #
24
- # # ...
25
- #
26
- # uploaded_file = MyUploader::UploadedFile.urlsafe_load(serialized)
27
- # uploaded_file #=> #<MyUploader::UploadedFile>
28
- #
29
- # ## Metadata
30
- #
31
- # By default no metadata is included in the serialization:
32
- #
33
- # uploaded_file.metadata #=> { ... metadata ... }
34
- #
35
- # serialized = MyUploader::UploadedFile.urlsafe_dump(uploaded_file)
36
- # uploaded_file = MyUploader::UploadedFile.urlsafe_load(serialized)
37
- #
38
- # uploaded_file.metadata #=> {}
39
- #
40
- # The `:metadata` option can be used to specify metadata you want to
41
- # serialize:
42
- #
43
- # serialized = MyUploader::UploadedFile.urlsafe_dump(uploaded_file, metadata: %w[size mime_type])
44
- # uploaded_file = MyUploader::UploadedFile.urlsafe_load(serialized)
45
- #
46
- # uploaded_file.metadata #=> { "size" => 4394, "mime_type" => "image/jpeg" }
47
- #
48
- # ## Signing
49
- #
50
- # By default the seralization is done with simple JSON + base64 encoding.
51
- # If you want to ensure the serialized data hasn't been tampred with, you
52
- # can have it signed with a secret key.
53
- #
54
- # plugin :urlsafe_serialization, secret_key: "my secret key"
55
- #
56
- # Now the `urlsafe_dump` will automatically sign serialized data with your
57
- # secret key, and `urlsafe_load` will automatically verify it.
58
- #
59
- # serialized = MyUploader::UploadedFile.urlsafe_dump(uploaded_file)
60
- # serialized #=> "<signature>--<json-base64-encoded-data>"
61
- #
62
- # uploaded_file = MyUploader::UploadedFile.urlsafe_load(serialized) # verifies the signature
63
- # uploaded_file #=> #<MyUploader::UploadedFile>
64
- #
65
- # If the signature is missing or invalid,
66
- # `Shrine::Plugins::UrlsafeSerialization::InvalidSignature` exception is
67
- # raised.
68
8
  module UrlsafeSerialization
69
- class InvalidSignature < Error; end
9
+ module ClassMethods
10
+ def urlsafe_serialize(hash)
11
+ urlsafe_serializer.encode(hash)
12
+ end
13
+
14
+ def urlsafe_deserialize(string)
15
+ urlsafe_serializer.decode(string)
16
+ end
70
17
 
71
- def self.configure(uploader, opts = {})
72
- uploader.opts[:urlsafe_serialization] ||= {}
73
- uploader.opts[:urlsafe_serialization].merge!(opts)
18
+ def urlsafe_serializer
19
+ Serializer.new
20
+ end
74
21
  end
75
22
 
76
23
  module FileMethods
77
24
  def urlsafe_dump(**options)
78
25
  self.class.urlsafe_dump(self, **options)
79
26
  end
27
+
28
+ def urlsafe_data(metadata: [])
29
+ data = self.data.dup
30
+
31
+ if metadata.any?
32
+ # order metadata in the specified order
33
+ data["metadata"] = metadata
34
+ .map { |name| [name, self.metadata[name]] }
35
+ .to_h
36
+ else
37
+ # save precious characters
38
+ data.delete("metadata")
39
+ end
40
+
41
+ data
42
+ end
80
43
  end
81
44
 
82
45
  module FileClassMethods
83
- def urlsafe_dump(file, metadata: [])
84
- data = file.data.dup
85
- data["metadata"] = metadata
86
- .map { |name| [name, file.metadata[name]] }
87
- .to_h
46
+ def urlsafe_dump(file, **options)
47
+ data = file.urlsafe_data(**options)
88
48
 
89
- urlsafe_serializer.dump(data)
49
+ shrine_class.urlsafe_serialize(data)
90
50
  end
91
51
 
92
52
  def urlsafe_load(string)
93
- data = urlsafe_serializer.load(string)
53
+ data = shrine_class.urlsafe_deserialize(string)
94
54
 
95
55
  new(data)
96
56
  end
97
-
98
- def urlsafe_serializer
99
- secret_key = shrine_class.opts[:urlsafe_serialization][:secret_key]
100
-
101
- if secret_key
102
- SecureSerializer.new(secret_key: secret_key)
103
- else
104
- Serializer.new
105
- end
106
- end
107
57
  end
108
58
 
109
59
  class Serializer
110
- def dump(data)
60
+ def encode(data)
111
61
  base64_encode(json_encode(data))
112
62
  end
113
63
 
114
- def load(data)
64
+ def decode(data)
115
65
  json_decode(base64_decode(data))
116
66
  end
117
67
 
@@ -133,48 +83,6 @@ class Shrine
133
83
  JSON.parse(data)
134
84
  end
135
85
  end
136
-
137
- class SecureSerializer < Serializer
138
- attr_reader :secret_key
139
-
140
- def initialize(secret_key:)
141
- @secret_key = secret_key
142
- end
143
-
144
- def dump(data)
145
- hmac_encode(super)
146
- end
147
-
148
- def load(data)
149
- super(hmac_decode(data))
150
- end
151
-
152
- def hmac_encode(data)
153
- "#{generate_hmac(data)}--#{data}"
154
- end
155
-
156
- def hmac_decode(data)
157
- data, hmac = data.split("--", 2).reverse
158
- verify_hmac(hmac, data)
159
- data
160
- end
161
-
162
- def verify_hmac(provided_hmac, data)
163
- if provided_hmac.nil?
164
- raise InvalidSignature, "signature is missing"
165
- end
166
-
167
- expected_hmac = generate_hmac(data)
168
-
169
- if provided_hmac != expected_hmac
170
- raise InvalidSignature, "provided signature doesn't match the expected"
171
- end
172
- end
173
-
174
- def generate_hmac(data)
175
- OpenSSL::HMAC.hexdigest(OpenSSL::Digest::SHA256.new, secret_key, data)
176
- end
177
- end
178
86
  end
179
87
 
180
88
  register_plugin(:_urlsafe_serialization, UrlsafeSerialization)
@@ -4,84 +4,6 @@ require "active_record"
4
4
 
5
5
  class Shrine
6
6
  module Plugins
7
- # The `activerecord` plugin extends the "attachment" interface with support
8
- # for ActiveRecord.
9
- #
10
- # plugin :activerecord
11
- #
12
- # ## Callbacks
13
- #
14
- # Now the attachment module will add additional callbacks to the model:
15
- #
16
- # * "before save" -- Used by the `recache` plugin.
17
- # * "after commit" (save) -- Promotes the attachment, deletes replaced ones.
18
- # * "after commit" (destroy) -- Deletes the attachment.
19
- #
20
- # Note that ActiveRecord versions 3.x and 4.x have errors automatically
21
- # silenced in hooks, which can make debugging more difficult, so it's
22
- # recommended that you enable errors:
23
- #
24
- # # This is the default in ActiveRecord 5
25
- # ActiveRecord::Base.raise_in_transactional_callbacks = true
26
- #
27
- # If you want to put promoting/deleting into a background job, see the
28
- # `backgrounding` plugin.
29
- #
30
- # Since attaching first saves the record with a cached attachment, then
31
- # saves again with a stored attachment, you can detect this in callbacks:
32
- #
33
- # class User < ActiveRecord::Base
34
- # include ImageUploader::Attachment.new(:avatar)
35
- #
36
- # before_save do
37
- # if avatar_data_changed? && avatar_attacher.cached?
38
- # # cached
39
- # elsif avatar_data_changed? && avatar_attacher.stored?
40
- # # promoted
41
- # end
42
- # end
43
- # end
44
- #
45
- # Note that ActiveRecord currently has a [bug with transaction callbacks],
46
- # so if you have any "after commit" callbacks, make sure to include Shrine's
47
- # attachment module *after* they have all been defined.
48
- #
49
- # If you don't want the attachment module to add any callbacks to the
50
- # model, and would instead prefer to call these actions manually, you can
51
- # disable callbacks:
52
- #
53
- # plugin :activerecord, callbacks: false
54
- #
55
- # ## Validations
56
- #
57
- # Additionally, any Shrine validation errors will be added to
58
- # ActiveRecord's errors upon validation. Note that Shrine validation
59
- # messages don't have to be strings, they can also be symbols or symbols
60
- # and options, which allows them to be internationalized together with
61
- # other ActiveRecord validation messages.
62
- #
63
- # class MyUploader < Shrine
64
- # plugin :validation_helpers
65
- #
66
- # Attacher.validate do
67
- # validate_max_size 256 * 1024**2, message: ->(max) { [:max_size, max: max] }
68
- # end
69
- # end
70
- #
71
- # If you want to validate presence of the attachment, you can do it
72
- # directly on the model.
73
- #
74
- # class User < ActiveRecord::Base
75
- # include ImageUploader::Attachment.new(:avatar)
76
- # validates_presence_of :avatar
77
- # end
78
- #
79
- # If don't want the attachment module to merge file validations errors into
80
- # model errors, you can disable it:
81
- #
82
- # plugin :activerecord, validations: false
83
- #
84
- # [bug with transaction callbacks]: https://github.com/rails/rails/issues/14493
85
7
  module Activerecord
86
8
  def self.configure(uploader, opts = {})
87
9
  uploader.opts[:activerecord_callbacks] = opts.fetch(:callbacks, uploader.opts.fetch(:activerecord_callbacks, true))
@@ -2,86 +2,6 @@
2
2
 
3
3
  class Shrine
4
4
  module Plugins
5
- # The `add_metadata` plugin provides a convenient method for extracting and
6
- # adding custom metadata values.
7
- #
8
- # plugin :add_metadata
9
- #
10
- # add_metadata :exif do |io, context|
11
- # begin
12
- # Exif::Data.new(io).to_h
13
- # rescue Exif::NotReadable # not a valid image
14
- # {}
15
- # end
16
- # end
17
- #
18
- # The above will add "exif" to the metadata hash, and also create the
19
- # `#exif` reader method on Shrine::UploadedFile.
20
- #
21
- # image.metadata["exif"]
22
- # # or
23
- # image.exif
24
- #
25
- # You can also extract multiple metadata values at once, by using
26
- # `add_metadata` without an argument and returning a hash of metadata.
27
- #
28
- # add_metadata do |io, context|
29
- # begin
30
- # data = Exif::Data.new(io)
31
- # rescue Exif::NotReadable # not a valid image
32
- # next {}
33
- # end
34
- #
35
- # { date_time: data.date_time,
36
- # flash: data.flash,
37
- # focal_length: data.focal_length,
38
- # exposure_time: data.exposure_time }
39
- # end
40
- #
41
- # In this case Shrine won't automatically create reader methods for the
42
- # extracted metadata on Shrine::UploadedFile, but you can create them via
43
- # `#metadata_method`.
44
- #
45
- # metadata_method :date_time, :flash
46
- #
47
- # The `io` might not always be a file object, so if you're using an
48
- # analyzer which requires the source file to be on disk, you can use
49
- # `Shrine.with_file` to ensure you have a file object.
50
- #
51
- # add_metadata do |io, context|
52
- # movie = Shrine.with_file(io) { |file| FFMPEG::Movie.new(file.path) }
53
- #
54
- # { "duration" => movie.duration,
55
- # "bitrate" => movie.bitrate,
56
- # "resolution" => movie.resolution,
57
- # "frame_rate" => movie.frame_rate }
58
- # end
59
- #
60
- # Any previously extracted metadata can be accessed via
61
- # `context[:metadata]`:
62
- #
63
- # add_metadata :foo do |io, context|
64
- # context[:metadata] #=>
65
- # # {
66
- # # "size" => 239823,
67
- # # "filename" => "nature.jpg",
68
- # # "mime_type" => "image/jpeg"
69
- # # }
70
- #
71
- # "foo"
72
- # end
73
- #
74
- # add_metadata :bar do |io, context|
75
- # context[:metadata] #=>
76
- # # {
77
- # # "size" => 239823,
78
- # # "filename" => "nature.jpg",
79
- # # "mime_type" => "image/jpeg",
80
- # # "foo" => "foo"
81
- # # }
82
- #
83
- # "bar"
84
- # end
85
5
  module AddMetadata
86
6
  def self.configure(uploader)
87
7
  uploader.opts[:metadata] ||= []
@@ -2,140 +2,6 @@
2
2
 
3
3
  class Shrine
4
4
  module Plugins
5
- # The `backgrounding` plugin enables you to move promoting and deleting of
6
- # files from record's lifecycle into background jobs. This is especially
7
- # useful if you're doing processing and/or you're storing files on an
8
- # external storage service.
9
- #
10
- # The plugin provides `Attacher.promote` and `Attacher.delete` methods,
11
- # which allow you to hook up to promoting and deleting and spawn background
12
- # jobs, by passing a block.
13
- #
14
- # Shrine.plugin :backgrounding
15
- #
16
- # # makes all uploaders use background jobs
17
- # Shrine::Attacher.promote { |data| PromoteJob.perform_async(data) }
18
- # Shrine::Attacher.delete { |data| DeleteJob.perform_async(data) }
19
- #
20
- # If you don't want to apply backgrounding for all uploaders, you can
21
- # declare the hooks only for specific uploaders (in this case it's still
22
- # recommended to keep the plugin loaded globally).
23
- #
24
- # class MyUploader < Shrine
25
- # # makes this uploader use background jobs
26
- # Attacher.promote { |data| PromoteJob.perform_async(data) }
27
- # Attacher.delete { |data| DeleteJob.perform_async(data) }
28
- # end
29
- #
30
- # The yielded `data` variable is a serializable hash containing all context
31
- # needed for promotion/deletion. Now you just need to declare the job
32
- # classes, and inside them call `Attacher.promote` or `Attacher.delete`,
33
- # this time with the received data.
34
- #
35
- # class PromoteJob
36
- # include Sidekiq::Worker
37
- # def perform(data)
38
- # Shrine::Attacher.promote(data)
39
- # end
40
- # end
41
- #
42
- # class DeleteJob
43
- # include Sidekiq::Worker
44
- # def perform(data)
45
- # Shrine::Attacher.delete(data)
46
- # end
47
- # end
48
- #
49
- # This example used Sidekiq, but obviously you could just as well use
50
- # any other backgrounding library. This setup will be applied globally for
51
- # all uploaders.
52
- #
53
- # If you're generating versions, and you want to process some versions in
54
- # the foreground before kicking off a background job, you can use the
55
- # `recache` plugin.
56
- #
57
- # In your application you can use `Attacher#cached?` and `Attacher#stored?`
58
- # to differentiate between your background job being in progress and
59
- # having completed.
60
- #
61
- # if user.avatar_attacher.cached? # background job is still in progress
62
- # # ...
63
- # elsif user.avatar_attacher.stored? # background job has finished
64
- # # ...
65
- # end
66
- #
67
- # ## `Attacher.promote` and `Attacher.delete`
68
- #
69
- # In background jobs, `Attacher.promote` and `Attacher.delete` will resolve
70
- # all necessary objects, and do the promotion/deletion. If
71
- # `Attacher.find_record` is defined (which comes with ORM plugins), model
72
- # instances will be treated as database records, with the `#id` attribute
73
- # assumed to represent the primary key. Then promotion will have the
74
- # following behaviour:
75
- #
76
- # 1. retrieves the database record
77
- # * if record is not found, it finishes
78
- # * if record is found but attachment has changed, it finishes
79
- # 2. uploads cached file to permanent storage
80
- # 3. reloads the database record
81
- # * if record is not found, it deletes the promoted files and finishes
82
- # * if record is found but attachment has changed, it deletes the promoted files and finishes
83
- # 4. updates the record with the promoted files
84
- #
85
- # Both `Attacher.promote` and `Attacher.delete` return a `Shrine::Attacher`
86
- # instance (if the action hasn't aborted), so you can use it to perform
87
- # additional tasks:
88
- #
89
- # def perform(data)
90
- # attacher = Shrine::Attacher.promote(data)
91
- # attacher.record.update(published: true) if attacher && attacher.record.is_a?(Post)
92
- # end
93
- #
94
- # ### Plain models
95
- #
96
- # You can also do backgrounding with plain models which don't represent
97
- # database records; the plugin will use that mode if `Attacher.find_record`
98
- # is not defined. In that case promotion will have the following behaviour:
99
- #
100
- # 1. instantiates the model
101
- # 2. uploads cached file to permanent storage
102
- # 3. writes promoted files to the model instance
103
- #
104
- # You can then retrieve the promoted files via the attacher object that
105
- # `Attacher.promote` returns, and do any additional tasks if you need to.
106
- #
107
- # ## `Attacher#_promote` and `Attacher#_delete`
108
- #
109
- # The plugin modifies `Attacher#_promote` and `Attacher#_delete` to call
110
- # the registered blocks with serializable attacher data, and these methods
111
- # are internally called by the attacher. `Attacher#promote` and
112
- # `Attacher#delete!` remain synchronous.
113
- #
114
- # # asynchronous (spawn background jobs)
115
- # attacher._promote
116
- # attacher._delete(attachment)
117
- #
118
- # # synchronous
119
- # attacher.promote
120
- # attacher.delete!(attachment)
121
- #
122
- # ## `Attacher.dump` and `Attacher.load`
123
- #
124
- # The plugin adds `Attacher.dump` and `Attacher.load` methods for
125
- # serializing attacher object and loading it back up. You can use them to
126
- # spawn background jobs for custom tasks.
127
- #
128
- # data = Shrine::Attacher.dump(attacher)
129
- # SomethingJob.perform_async(data)
130
- #
131
- # # ...
132
- #
133
- # class SomethingJob
134
- # def perform(data)
135
- # attacher = Shrine::Attacher.load(data)
136
- # # ...
137
- # end
138
- # end
139
5
  module Backgrounding
140
6
  module AttacherClassMethods
141
7
  # If block is passed in, stores it to be called on promotion. Otherwise