shrine 3.0.0.rc → 3.0.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 (167) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +10 -66
  3. data/README.md +39 -1061
  4. data/doc/advantages.md +151 -148
  5. data/doc/attacher.md +12 -30
  6. data/doc/carrierwave.md +150 -115
  7. data/doc/changing_derivatives.md +5 -11
  8. data/doc/changing_location.md +8 -5
  9. data/doc/changing_storage.md +5 -2
  10. data/doc/creating_persistence_plugins.md +9 -6
  11. data/doc/creating_plugins.md +42 -22
  12. data/doc/creating_storages.md +4 -1
  13. data/doc/design.md +7 -5
  14. data/doc/direct_s3.md +9 -4
  15. data/doc/external/articles.md +50 -0
  16. data/doc/external/extensions.md +46 -0
  17. data/doc/external/misc.md +17 -0
  18. data/doc/getting_started.md +1038 -0
  19. data/doc/metadata.md +5 -3
  20. data/doc/multiple_files.md +55 -29
  21. data/doc/paperclip.md +206 -163
  22. data/doc/plugins/activerecord.md +26 -6
  23. data/doc/plugins/add_metadata.md +4 -2
  24. data/doc/plugins/atomic_helpers.md +4 -2
  25. data/doc/plugins/backgrounding.md +83 -44
  26. data/doc/plugins/cached_attachment_data.md +4 -2
  27. data/doc/plugins/column.md +4 -2
  28. data/doc/plugins/data_uri.md +10 -6
  29. data/doc/plugins/default_storage.md +5 -3
  30. data/doc/plugins/default_url.md +4 -2
  31. data/doc/plugins/delete_raw.md +4 -2
  32. data/doc/plugins/derivation_endpoint.md +63 -39
  33. data/doc/plugins/derivatives.md +13 -50
  34. data/doc/plugins/determine_mime_type.md +6 -4
  35. data/doc/plugins/download_endpoint.md +6 -3
  36. data/doc/plugins/dynamic_storage.md +4 -2
  37. data/doc/plugins/entity.md +6 -4
  38. data/doc/plugins/form_assign.md +4 -2
  39. data/doc/plugins/included.md +4 -2
  40. data/doc/plugins/infer_extension.md +6 -4
  41. data/doc/plugins/instrumentation.md +5 -3
  42. data/doc/plugins/keep_files.md +9 -2
  43. data/doc/plugins/metadata_attributes.md +5 -3
  44. data/doc/plugins/mirroring.md +4 -2
  45. data/doc/plugins/model.md +6 -4
  46. data/doc/plugins/module_include.md +4 -2
  47. data/doc/plugins/multi_cache.md +4 -2
  48. data/doc/plugins/persistence.md +5 -3
  49. data/doc/plugins/presign_endpoint.md +6 -2
  50. data/doc/plugins/pretty_location.md +5 -3
  51. data/doc/plugins/processing.md +4 -2
  52. data/doc/plugins/rack_file.md +8 -2
  53. data/doc/plugins/rack_response.md +6 -2
  54. data/doc/plugins/recache.md +4 -2
  55. data/doc/plugins/refresh_metadata.md +5 -3
  56. data/doc/plugins/remote_url.md +26 -5
  57. data/doc/plugins/remove_attachment.md +4 -2
  58. data/doc/plugins/remove_invalid.md +10 -2
  59. data/doc/plugins/restore_cached_data.md +9 -3
  60. data/doc/plugins/sequel.md +26 -6
  61. data/doc/plugins/signature.md +6 -4
  62. data/doc/plugins/store_dimensions.md +6 -4
  63. data/doc/plugins/tempfile.md +4 -2
  64. data/doc/plugins/upload_endpoint.md +6 -2
  65. data/doc/plugins/upload_options.md +6 -4
  66. data/doc/plugins/url_options.md +4 -2
  67. data/doc/plugins/validation.md +7 -3
  68. data/doc/plugins/validation_helpers.md +13 -10
  69. data/doc/plugins/versions.md +4 -8
  70. data/doc/processing.md +27 -9
  71. data/doc/refile.md +119 -127
  72. data/doc/release_notes/1.0.0.md +4 -0
  73. data/doc/release_notes/1.1.0.md +4 -0
  74. data/doc/release_notes/1.2.0.md +4 -0
  75. data/doc/release_notes/1.3.0.md +4 -0
  76. data/doc/release_notes/1.4.0.md +4 -0
  77. data/doc/release_notes/1.4.1.md +4 -0
  78. data/doc/release_notes/1.4.2.md +4 -0
  79. data/doc/release_notes/2.0.0.md +4 -0
  80. data/doc/release_notes/2.0.1.md +4 -0
  81. data/doc/release_notes/2.1.0.md +4 -0
  82. data/doc/release_notes/2.1.1.md +4 -0
  83. data/doc/release_notes/2.10.0.md +4 -0
  84. data/doc/release_notes/2.10.1.md +4 -0
  85. data/doc/release_notes/2.11.0.md +4 -0
  86. data/doc/release_notes/2.12.0.md +4 -0
  87. data/doc/release_notes/2.13.0.md +4 -0
  88. data/doc/release_notes/2.14.0.md +5 -1
  89. data/doc/release_notes/2.15.0.md +10 -6
  90. data/doc/release_notes/2.16.0.md +4 -0
  91. data/doc/release_notes/2.17.0.md +4 -0
  92. data/doc/release_notes/2.18.0.md +4 -0
  93. data/doc/release_notes/2.19.0.md +7 -4
  94. data/doc/release_notes/2.2.0.md +4 -0
  95. data/doc/release_notes/2.3.0.md +4 -0
  96. data/doc/release_notes/2.3.1.md +4 -0
  97. data/doc/release_notes/2.4.0.md +4 -0
  98. data/doc/release_notes/2.4.1.md +4 -0
  99. data/doc/release_notes/2.5.0.md +4 -0
  100. data/doc/release_notes/2.6.0.md +4 -0
  101. data/doc/release_notes/2.6.1.md +4 -0
  102. data/doc/release_notes/2.7.0.md +4 -0
  103. data/doc/release_notes/2.8.0.md +4 -0
  104. data/doc/release_notes/2.9.0.md +4 -0
  105. data/doc/release_notes/3.0.0.md +120 -38
  106. data/doc/retrieving_uploads.md +4 -1
  107. data/doc/securing_uploads.md +4 -1
  108. data/doc/storage/file_system.md +12 -4
  109. data/doc/storage/s3.md +4 -2
  110. data/doc/testing.md +27 -41
  111. data/doc/upgrading_to_3.md +105 -26
  112. data/doc/validation.md +8 -6
  113. data/lib/shrine/attacher.rb +2 -2
  114. data/lib/shrine/attachment.rb +7 -10
  115. data/lib/shrine/plugins/activerecord.rb +10 -10
  116. data/lib/shrine/plugins/add_metadata.rb +1 -3
  117. data/lib/shrine/plugins/atomic_helpers.rb +6 -8
  118. data/lib/shrine/plugins/backgrounding.rb +4 -6
  119. data/lib/shrine/plugins/cached_attachment_data.rb +1 -3
  120. data/lib/shrine/plugins/column.rb +2 -4
  121. data/lib/shrine/plugins/data_uri.rb +1 -3
  122. data/lib/shrine/plugins/default_storage.rb +1 -3
  123. data/lib/shrine/plugins/default_url.rb +1 -3
  124. data/lib/shrine/plugins/delete_raw.rb +1 -3
  125. data/lib/shrine/plugins/derivation_endpoint.rb +3 -4
  126. data/lib/shrine/plugins/derivatives.rb +2 -4
  127. data/lib/shrine/plugins/determine_mime_type.rb +1 -3
  128. data/lib/shrine/plugins/download_endpoint.rb +1 -3
  129. data/lib/shrine/plugins/dynamic_storage.rb +1 -3
  130. data/lib/shrine/plugins/entity.rb +25 -9
  131. data/lib/shrine/plugins/form_assign.rb +1 -3
  132. data/lib/shrine/plugins/included.rb +1 -3
  133. data/lib/shrine/plugins/infer_extension.rb +1 -3
  134. data/lib/shrine/plugins/instrumentation.rb +1 -3
  135. data/lib/shrine/plugins/keep_files.rb +1 -3
  136. data/lib/shrine/plugins/metadata_attributes.rb +1 -3
  137. data/lib/shrine/plugins/mirroring.rb +2 -1
  138. data/lib/shrine/plugins/model.rb +2 -4
  139. data/lib/shrine/plugins/module_include.rb +1 -3
  140. data/lib/shrine/plugins/multi_cache.rb +3 -3
  141. data/lib/shrine/plugins/presign_endpoint.rb +1 -3
  142. data/lib/shrine/plugins/pretty_location.rb +1 -3
  143. data/lib/shrine/plugins/processing.rb +1 -3
  144. data/lib/shrine/plugins/rack_file.rb +1 -3
  145. data/lib/shrine/plugins/rack_response.rb +1 -3
  146. data/lib/shrine/plugins/recache.rb +1 -3
  147. data/lib/shrine/plugins/refresh_metadata.rb +1 -3
  148. data/lib/shrine/plugins/remote_url.rb +1 -3
  149. data/lib/shrine/plugins/remove_attachment.rb +1 -3
  150. data/lib/shrine/plugins/remove_invalid.rb +1 -3
  151. data/lib/shrine/plugins/restore_cached_data.rb +1 -3
  152. data/lib/shrine/plugins/sequel.rb +10 -12
  153. data/lib/shrine/plugins/signature.rb +1 -3
  154. data/lib/shrine/plugins/store_dimensions.rb +1 -3
  155. data/lib/shrine/plugins/tempfile.rb +1 -3
  156. data/lib/shrine/plugins/upload_endpoint.rb +1 -3
  157. data/lib/shrine/plugins/upload_options.rb +1 -3
  158. data/lib/shrine/plugins/url_options.rb +1 -3
  159. data/lib/shrine/plugins/validation.rb +1 -3
  160. data/lib/shrine/plugins/validation_helpers.rb +1 -3
  161. data/lib/shrine/plugins/versions.rb +1 -3
  162. data/lib/shrine/storage/file_system.rb +1 -1
  163. data/lib/shrine/storage/linter.rb +1 -1
  164. data/lib/shrine/storage/memory.rb +2 -1
  165. data/lib/shrine/storage/s3.rb +3 -3
  166. data/lib/shrine/version.rb +1 -1
  167. metadata +8 -4
@@ -4,9 +4,7 @@ require "active_record"
4
4
 
5
5
  class Shrine
6
6
  module Plugins
7
- # Documentation lives in [doc/plugins/activerecord.md] on GitHub.
8
- #
9
- # [doc/plugins/activerecord.md]: https://github.com/shrinerb/shrine/blob/master/doc/plugins/activerecord.md
7
+ # Documentation can be found on https://shrinerb.com/docs/plugins/activerecord
10
8
  module Activerecord
11
9
  def self.load_dependencies(uploader, **)
12
10
  uploader.plugin :model
@@ -34,17 +32,23 @@ class Shrine
34
32
 
35
33
  if shrine_class.opts[:activerecord][:callbacks]
36
34
  model.before_save do
37
- send(:"#{name}_attacher").send(:activerecord_before_save)
35
+ if send(:"#{name}_attacher").changed?
36
+ send(:"#{name}_attacher").send(:activerecord_before_save)
37
+ end
38
38
  end
39
39
 
40
40
  [:create, :update].each do |action|
41
41
  model.after_commit on: action do
42
- send(:"#{name}_attacher").send(:activerecord_after_save)
42
+ if send(:"#{name}_attacher").changed?
43
+ send(:"#{name}_attacher").send(:activerecord_after_save)
44
+ end
43
45
  end
44
46
  end
45
47
 
46
48
  model.after_commit on: :destroy do
47
- send(:"#{name}_attacher").send(:activerecord_after_destroy)
49
+ if send(:"#{name}_attacher").attached?
50
+ send(:"#{name}_attacher").send(:activerecord_after_destroy)
51
+ end
48
52
  end
49
53
  end
50
54
 
@@ -78,15 +82,11 @@ class Shrine
78
82
 
79
83
  # Calls Attacher#save. Called before model save.
80
84
  def activerecord_before_save
81
- return unless changed?
82
-
83
85
  save
84
86
  end
85
87
 
86
88
  # Finalizes attachment and persists changes. Called after model save.
87
89
  def activerecord_after_save
88
- return unless changed?
89
-
90
90
  finalize
91
91
  persist
92
92
  end
@@ -2,9 +2,7 @@
2
2
 
3
3
  class Shrine
4
4
  module Plugins
5
- # Documentation lives in [doc/plugins/add_metadata.md] on GitHub.
6
- #
7
- # [doc/plugins/add_metadata.md]: https://github.com/shrinerb/shrine/blob/master/doc/plugins/add_metadata.md
5
+ # Documentation can be found on https://shrinerb.com/docs/plugins/add_metadata
8
6
  module AddMetadata
9
7
  def self.configure(uploader)
10
8
  uploader.opts[:add_metadata] ||= { definitions: [] }
@@ -5,9 +5,7 @@ class Shrine
5
5
  end
6
6
 
7
7
  module Plugins
8
- # Documentation lives in [doc/plugins/atomic_helpers.md] on GitHub.
9
- #
10
- # [doc/plugins/atomic_helpers.md]: https://github.com/shrinerb/shrine/blob/master/doc/plugins/atomic_helpers.md
8
+ # Documentation can be found on https://shrinerb.com/docs/plugins/atomic_helpers
11
9
  class AtomicHelpers
12
10
  module AttacherClassMethods
13
11
  # Retrieves the attacher from the given entity/model and verifies that
@@ -43,8 +41,8 @@ class Shrine
43
41
  # persist: persist_strategy,
44
42
  # )
45
43
  #
46
- # This more convenient to use with ORM plugins, which provide defaults
47
- # for reloading and persistence.
44
+ # This more convenient to use with concrete persistence plugins, which
45
+ # provide defaults for reloading and persistence.
48
46
  def abstract_atomic_promote(reload:, persist:, **options, &block)
49
47
  original_file = file
50
48
 
@@ -68,8 +66,8 @@ class Shrine
68
66
  # persist: persist_strategy,
69
67
  # )
70
68
  #
71
- # This more convenient to use with ORM plugins, which provide defaults
72
- # for reloading and persistence.
69
+ # This more convenient to use with concrete persistence plugins, which
70
+ # provide defaults for reloading and persistence.
73
71
  def abstract_atomic_persist(original_file = file, reload:, persist:)
74
72
  abstract_reload(reload) do |attacher|
75
73
  if attacher && attacher.file != original_file
@@ -89,7 +87,7 @@ class Shrine
89
87
  #
90
88
  # attacher.file_data #=> { "id" => "abc123.jpg", "storage" => "store" }
91
89
  def file_data
92
- file!.data.reject { |key, value| key == "metadata" }
90
+ file!.data.reject { |key, _| key == "metadata" }
93
91
  end
94
92
 
95
93
  protected
@@ -2,9 +2,7 @@
2
2
 
3
3
  class Shrine
4
4
  module Plugins
5
- # Documentation lives in [doc/plugins/backgrounding.md] on GitHub.
6
- #
7
- # [doc/plugins/backgrounding.md]: https://github.com/shrinerb/shrine/blob/master/doc/plugins/backgrounding.md
5
+ # Documentation can be found on https://shrinerb.com/docs/plugins/backgrounding
8
6
  module Backgrounding
9
7
  def self.configure(uploader)
10
8
  uploader.opts[:backgrounding] ||= {}
@@ -71,7 +69,7 @@ class Shrine
71
69
  # Does a background promote if promote block was registered.
72
70
  def promote_cached(**options)
73
71
  if promote? && promote_block
74
- promote_background(**options)
72
+ promote_background
75
73
  else
76
74
  super
77
75
  end
@@ -94,10 +92,10 @@ class Shrine
94
92
  end
95
93
 
96
94
  # Calls the registered destroy block.
97
- def destroy_background
95
+ def destroy_background(**options)
98
96
  fail Error, "destroy block is not registered" unless destroy_block
99
97
 
100
- background_block(destroy_block)
98
+ background_block(destroy_block, **options)
101
99
  end
102
100
 
103
101
  private
@@ -2,9 +2,7 @@
2
2
 
3
3
  class Shrine
4
4
  module Plugins
5
- # Documentation lives in [doc/plugins/cached_attachment_data.md] on GitHub.
6
- #
7
- # [doc/plugins/cached_attachment_data.md]: https://github.com/shrinerb/shrine/blob/master/doc/plugins/cached_attachment_data.md
5
+ # Documentation can be found on https://shrinerb.com/docs/plugins/cached_attachment_data
8
6
  module CachedAttachmentData
9
7
  module AttachmentMethods
10
8
  def define_model_methods(name)
@@ -4,9 +4,7 @@ require "json"
4
4
 
5
5
  class Shrine
6
6
  module Plugins
7
- # Documentation lives in [doc/plugins/column.md] on GitHub.
8
- #
9
- # [doc/plugins/column.md]: https://github.com/shrinerb/shrine/blob/master/doc/plugins/column.md
7
+ # Documentation can be found on https://shrinerb.com/docs/plugins/column
10
8
  module Column
11
9
  def self.configure(uploader, **opts)
12
10
  uploader.opts[:column] ||= { serializer: JsonSerializer }
@@ -77,7 +75,7 @@ class Shrine
77
75
  # Attacher.deserialize_column(nil)
78
76
  # #=> nil
79
77
  def deserialize_column(data)
80
- if column_serializer && data.is_a?(String)
78
+ if column_serializer && data && !data.is_a?(Hash)
81
79
  column_serializer.load(data)
82
80
  else
83
81
  data&.to_hash
@@ -8,9 +8,7 @@ require "forwardable"
8
8
 
9
9
  class Shrine
10
10
  module Plugins
11
- # Documentation lives in [doc/plugins/data_uri.md] on GitHub.
12
- #
13
- # [doc/plugins/data_uri.md]: https://github.com/shrinerb/shrine/blob/master/doc/plugins/data_uri.md
11
+ # Documentation can be found on https://shrinerb.com/docs/plugins/data_uri
14
12
  module DataUri
15
13
  class ParseError < Error; end
16
14
 
@@ -2,9 +2,7 @@
2
2
 
3
3
  class Shrine
4
4
  module Plugins
5
- # Documentation lives in [doc/plugins/default_storage.md] on GitHub.
6
- #
7
- # [doc/plugins/default_storage.md]: https://github.com/shrinerb/shrine/blob/master/doc/plugins/default_storage.md
5
+ # Documentation can be found on https://shrinerb.com/docs/plugins/default_storage
8
6
  module DefaultStorage
9
7
  def self.configure(uploader, **opts)
10
8
  uploader.opts[:default_storage] ||= {}
@@ -2,9 +2,7 @@
2
2
 
3
3
  class Shrine
4
4
  module Plugins
5
- # Documentation lives in [doc/plugins/default_url.md] on GitHub.
6
- #
7
- # [doc/plugins/default_url.md]: https://github.com/shrinerb/shrine/blob/master/doc/plugins/default_url.md
5
+ # Documentation can be found on https://shrinerb.com/docs/plugins/default_url
8
6
  module DefaultUrl
9
7
  def self.configure(uploader, **opts)
10
8
  uploader.opts[:default_url] ||= {}
@@ -4,9 +4,7 @@ Shrine.deprecation("The delete_raw plugin is deprecated and will be removed in S
4
4
 
5
5
  class Shrine
6
6
  module Plugins
7
- # Documentation lives in [doc/plugins/delete_raw.md] on GitHub.
8
- #
9
- # [doc/plugins/delete_raw.md]: https://github.com/shrinerb/shrine/blob/master/doc/plugins/delete_raw.md
7
+ # Documentation can be found on https://shrinerb.com/docs/plugins/delete_raw
10
8
  module DeleteRaw
11
9
  def self.configure(uploader, **opts)
12
10
  uploader.opts[:delete_raw] ||= {}
@@ -9,9 +9,7 @@ require "pathname"
9
9
 
10
10
  class Shrine
11
11
  module Plugins
12
- # Documentation lives in [doc/plugins/derivation_endpoint.md] on GitHub.
13
- #
14
- # [doc/plugins/derivation_endpoint.md]: https://github.com/shrinerb/shrine/blob/master/doc/plugins/derivation_endpoint.md
12
+ # Documentation can be found on https://shrinerb.com/docs/plugins/derivation_endpoint
15
13
  module DerivationEndpoint
16
14
  LOG_SUBSCRIBER = -> (event) do
17
15
  Shrine.logger.info "Derivation (#{event.duration}ms) – #{{
@@ -517,7 +515,7 @@ class Shrine
517
515
 
518
516
  [302, { "Location" => redirect_url }, []]
519
517
  else
520
- if derivative
518
+ if derivative && File.exist?(derivative.path)
521
519
  file_response(derivative, env)
522
520
  else
523
521
  uploaded_file.to_rack_response(
@@ -653,6 +651,7 @@ class Shrine
653
651
  shrine_class.upload io, upload_storage,
654
652
  location: upload_location,
655
653
  upload_options: upload_options,
654
+ action: :derivation,
656
655
  **options
657
656
  end
658
657
  end
@@ -2,9 +2,7 @@
2
2
 
3
3
  class Shrine
4
4
  module Plugins
5
- # Documentation lives in [doc/plugins/derivatives.md] on GitHub.
6
- #
7
- # [doc/plugins/derivatives.md]: https://github.com/shrinerb/shrine/blob/master/doc/plugins/derivatives.md
5
+ # Documentation can be found on https://shrinerb.com/docs/plugins/derivatives
8
6
  module Derivatives
9
7
  NOOP_PROCESSOR = -> (*) { Hash.new }
10
8
 
@@ -244,7 +242,7 @@ class Shrine
244
242
  file.open if file.is_a?(Tempfile) # refresh file descriptor
245
243
  file.binmode if file.respond_to?(:binmode) # ensure binary mode
246
244
 
247
- upload(file, storage, derivative: path, delete: true, **options)
245
+ upload(file, storage, derivative: path, delete: true, action: :derivatives, **options)
248
246
  end
249
247
 
250
248
  # Downloads the attached file and calls the specified processor.
@@ -2,9 +2,7 @@
2
2
 
3
3
  class Shrine
4
4
  module Plugins
5
- # Documentation lives in [doc/plugins/determine_mime_type.md] on GitHub.
6
- #
7
- # [doc/plugins/determine_mime_type.md]: https://github.com/shrinerb/shrine/blob/master/doc/plugins/determine_mime_type.md
5
+ # Documentation can be found on https://shrinerb.com/docs/plugins/determine_mime_type
8
6
  module DetermineMimeType
9
7
  LOG_SUBSCRIBER = -> (event) do
10
8
  Shrine.logger.info "MIME Type (#{event.duration}ms) – #{{
@@ -2,9 +2,7 @@
2
2
 
3
3
  class Shrine
4
4
  module Plugins
5
- # Documentation lives in [doc/plugins/download_endpoint.md] on GitHub.
6
- #
7
- # [doc/plugins/download_endpoint.md]: https://github.com/shrinerb/shrine/blob/master/doc/plugins/download_endpoint.md
5
+ # Documentation can be found on https://shrinerb.com/docs/plugins/download_endpoint
8
6
  module DownloadEndpoint
9
7
  def self.load_dependencies(uploader, **)
10
8
  uploader.plugin :rack_response
@@ -2,9 +2,7 @@
2
2
 
3
3
  class Shrine
4
4
  module Plugins
5
- # Documentation lives in [doc/plugins/dynamic_storage.md] on GitHub.
6
- #
7
- # [doc/plugins/dynamic_storage.md]: https://github.com/shrinerb/shrine/blob/master/doc/plugins/dynamic_storage.md
5
+ # Documentation can be found on https://shrinerb.com/docs/plugins/dynamic_storage
8
6
  module DynamicStorage
9
7
  def self.configure(uploader)
10
8
  uploader.opts[:dynamic_storage] ||= { resolvers: {} }
@@ -2,21 +2,31 @@
2
2
 
3
3
  class Shrine
4
4
  module Plugins
5
- # Documentation lives in [doc/plugins/entity.md] on GitHub.
6
- #
7
- # [doc/plugins/entity.md]: https://github.com/shrinerb/shrine/blob/master/doc/plugins/entity.md
5
+ # Documentation can be found on https://shrinerb.com/docs/plugins/entity
8
6
  module Entity
9
7
  def self.load_dependencies(uploader, **)
10
8
  uploader.plugin :column
11
9
  end
12
10
 
13
11
  module AttachmentMethods
12
+ # Defines instance methods on initialization.
14
13
  def initialize(name, **options)
15
- super(name, **options)
14
+ super
16
15
 
17
16
  define_entity_methods(name)
18
17
  end
19
18
 
19
+ # Defines class methods on inclusion.
20
+ def included(klass)
21
+ super
22
+
23
+ attachment = self
24
+
25
+ klass.send(:define_singleton_method, :"#{@name}_attacher") do |**options|
26
+ attachment.send(:class_attacher, **options)
27
+ end
28
+ end
29
+
20
30
  private
21
31
 
22
32
  # Defines `#<name>`, `#<name>_url`, and `#<name>_attacher` methods.
@@ -41,13 +51,21 @@ class Shrine
41
51
  end
42
52
  end
43
53
 
44
- # Creates an instance of the corresponding Attacher subclass. It's not
54
+ # Returns the class attacher instance with loaded entity. It's not
45
55
  # memoized because the entity object could be frozen.
46
56
  def attacher(record, options)
47
- attacher = record.class.send(:"#{@name}_attacher", options)
57
+ attacher = class_attacher(options)
48
58
  attacher.load_entity(record, @name)
49
59
  attacher
50
60
  end
61
+
62
+ # Creates an instance of the corresponding attacher class with set
63
+ # name.
64
+ def class_attacher(options)
65
+ attacher = shrine_class::Attacher.new(**@options, **options)
66
+ attacher.instance_variable_set(:@name, @name)
67
+ attacher
68
+ end
51
69
  end
52
70
 
53
71
  module AttacherClassMethods
@@ -111,9 +129,7 @@ class Shrine
111
129
  # attacher = Shrine::Attacher.from_entity(photo, :image)
112
130
  # attacher.attribute #=> :image_data
113
131
  def attribute
114
- fail Shrine::Error, "record is not loaded" if name.nil?
115
-
116
- :"#{name}_data"
132
+ :"#{name}_data" if name
117
133
  end
118
134
 
119
135
  private
@@ -2,9 +2,7 @@
2
2
 
3
3
  class Shrine
4
4
  module Plugins
5
- # Documentation lives in [doc/plugins/form_assign.md] on GitHub.
6
- #
7
- # [doc/plugins/form_assign.md]: https://github.com/shrinerb/shrine/blob/master/doc/plugins/form_assign.md
5
+ # Documentation can be found on https://shrinerb.com/docs/plugins/form_assign
8
6
  module FormAssign
9
7
  def self.load_dependencies(uploader)
10
8
  uploader.plugin :entity
@@ -2,9 +2,7 @@
2
2
 
3
3
  class Shrine
4
4
  module Plugins
5
- # Documentation lives in [doc/plugins/included.md] on GitHub.
6
- #
7
- # [doc/plugins/included.md]: https://github.com/shrinerb/shrine/blob/master/doc/plugins/included.md
5
+ # Documentation can be found on https://shrinerb.com/docs/plugins/included
8
6
  module Included
9
7
  def self.configure(uploader, &block)
10
8
  uploader.opts[:included] ||= {}
@@ -4,9 +4,7 @@ require "pathname"
4
4
 
5
5
  class Shrine
6
6
  module Plugins
7
- # Documentation lives in [doc/plugins/infer_extension.md] on GitHub.
8
- #
9
- # [doc/plugins/infer_extension.md]: https://github.com/shrinerb/shrine/blob/master/doc/plugins/infer_extension.md
7
+ # Documentation can be found on https://shrinerb.com/docs/plugins/infer_extension
10
8
  module InferExtension
11
9
  LOG_SUBSCRIBER = -> (event) do
12
10
  Shrine.logger.info "Extension (#{event.duration}ms) – #{{
@@ -2,9 +2,7 @@
2
2
 
3
3
  class Shrine
4
4
  module Plugins
5
- # Documentation lives in [doc/plugins/instrumentation.md] on GitHub.
6
- #
7
- # [doc/plugins/instrumentation.md]: https://github.com/shrinerb/shrine/blob/master/doc/plugins/instrumentation.md
5
+ # Documentation can be found on https://shrinerb.com/docs/plugins/instrumentation
8
6
  module Instrumentation
9
7
  EVENTS = %i[upload download open exists delete metadata].freeze
10
8
 
@@ -2,9 +2,7 @@
2
2
 
3
3
  class Shrine
4
4
  module Plugins
5
- # Documentation lives in [doc/plugins/keep_files.md] on GitHub.
6
- #
7
- # [doc/plugins/keep_files.md]: https://github.com/shrinerb/shrine/blob/master/doc/plugins/keep_files.md
5
+ # Documentation can be found on https://shrinerb.com/docs/plugins/keep_files
8
6
  module KeepFiles
9
7
  module AttacherMethods
10
8
  def destroy?
@@ -2,9 +2,7 @@
2
2
 
3
3
  class Shrine
4
4
  module Plugins
5
- # Documentation lives in [doc/plugins/metadata_attributes.md] on GitHub.
6
- #
7
- # [doc/plugins/metadata_attributes.md]: https://github.com/shrinerb/shrine/blob/master/doc/plugins/metadata_attributes.md
5
+ # Documentation can be found on https://shrinerb.com/docs/plugins/metadata_attributes
8
6
  module MetadataAttributes
9
7
  def self.load_dependencies(uploader, *)
10
8
  uploader.plugin :entity
@@ -2,6 +2,7 @@
2
2
 
3
3
  class Shrine
4
4
  module Plugins
5
+ # Documentation can be found on https://shrinerb.com/docs/plugins/mirroring
5
6
  module Mirroring
6
7
  def self.configure(uploader, **opts)
7
8
  uploader.opts[:mirroring] ||= { upload: true, delete: true }
@@ -84,7 +85,7 @@ class Shrine
84
85
  each_mirror do |mirror|
85
86
  rewind if opened?
86
87
 
87
- shrine_class.upload(self, mirror, location: id, close: false)
88
+ shrine_class.upload(self, mirror, location: id, close: false, action: :mirror)
88
89
  end
89
90
  ensure
90
91
  if opened? && !previously_opened