shrine 2.2.0 → 2.3.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.
- checksums.yaml +4 -4
- data/README.md +143 -84
- data/doc/carrierwave.md +187 -47
- data/doc/direct_s3.md +57 -39
- data/doc/paperclip.md +183 -91
- data/doc/refile.md +148 -124
- data/doc/regenerating_versions.md +2 -3
- data/lib/shrine.rb +26 -28
- data/lib/shrine/plugins/activerecord.rb +22 -31
- data/lib/shrine/plugins/add_metadata.rb +1 -1
- data/lib/shrine/plugins/backgrounding.rb +19 -7
- data/lib/shrine/plugins/backup.rb +2 -2
- data/lib/shrine/plugins/cached_attachment_data.rb +1 -1
- data/lib/shrine/plugins/copy.rb +52 -0
- data/lib/shrine/plugins/data_uri.rb +1 -1
- data/lib/shrine/plugins/default_storage.rb +2 -2
- data/lib/shrine/plugins/default_url.rb +1 -1
- data/lib/shrine/plugins/default_url_options.rb +1 -1
- data/lib/shrine/plugins/delete_promoted.rb +1 -1
- data/lib/shrine/plugins/delete_raw.rb +1 -1
- data/lib/shrine/plugins/determine_mime_type.rb +3 -2
- data/lib/shrine/plugins/direct_upload.rb +36 -24
- data/lib/shrine/plugins/download_endpoint.rb +3 -3
- data/lib/shrine/plugins/dynamic_storage.rb +2 -2
- data/lib/shrine/plugins/hooks.rb +1 -1
- data/lib/shrine/plugins/included.rb +3 -4
- data/lib/shrine/plugins/keep_files.rb +1 -1
- data/lib/shrine/plugins/logging.rb +1 -1
- data/lib/shrine/plugins/module_include.rb +1 -1
- data/lib/shrine/plugins/moving.rb +10 -5
- data/lib/shrine/plugins/multi_delete.rb +2 -2
- data/lib/shrine/plugins/parallelize.rb +2 -2
- data/lib/shrine/plugins/parsed_json.rb +1 -1
- data/lib/shrine/plugins/pretty_location.rb +1 -1
- data/lib/shrine/plugins/processing.rb +11 -9
- data/lib/shrine/plugins/rack_file.rb +1 -1
- data/lib/shrine/plugins/recache.rb +14 -4
- data/lib/shrine/plugins/remote_url.rb +1 -1
- data/lib/shrine/plugins/remove_attachment.rb +3 -4
- data/lib/shrine/plugins/remove_invalid.rb +1 -1
- data/lib/shrine/plugins/restore_cached_data.rb +11 -4
- data/lib/shrine/plugins/sequel.rb +34 -45
- data/lib/shrine/plugins/store_dimensions.rb +1 -1
- data/lib/shrine/plugins/upload_options.rb +2 -2
- data/lib/shrine/plugins/validation_helpers.rb +7 -8
- data/lib/shrine/plugins/versions.rb +31 -30
- data/lib/shrine/storage/file_system.rb +16 -12
- data/lib/shrine/storage/s3.rb +36 -2
- data/lib/shrine/version.rb +1 -1
- data/shrine.gemspec +9 -8
- metadata +11 -9
@@ -3,14 +3,14 @@ require "down"
|
|
3
3
|
|
4
4
|
class Shrine
|
5
5
|
module Plugins
|
6
|
-
# The download_endpoint plugin provides a
|
6
|
+
# The `download_endpoint` plugin provides a Rack endpoint for downloading
|
7
7
|
# uploaded files from specified storages. This can be useful when files
|
8
8
|
# from your storages aren't accessible over URL (e.g. database storages) or
|
9
|
-
# if you want to authenticate your downloads.
|
9
|
+
# if you want to authenticate your downloads. It requires the [Roda] gem.
|
10
10
|
#
|
11
11
|
# plugin :download_endpoint, storages: [:store], prefix: "attachments"
|
12
12
|
#
|
13
|
-
# After loading the plugin the endpoint
|
13
|
+
# After loading the plugin the endpoint can be mounted:
|
14
14
|
#
|
15
15
|
# Rails.appliations.routes.draw do
|
16
16
|
# mount Shrine::DownloadEndpoint => "/attachments"
|
@@ -1,6 +1,6 @@
|
|
1
1
|
class Shrine
|
2
2
|
module Plugins
|
3
|
-
# The dynamic_storage plugin allows you to register a storage using a
|
3
|
+
# The `dynamic_storage` plugin allows you to register a storage using a
|
4
4
|
# regex, and evaluate the storage class dynamically depending on the regex.
|
5
5
|
#
|
6
6
|
# Example:
|
@@ -16,7 +16,7 @@ class Shrine
|
|
16
16
|
# saves files to the bucket "foo". The block is yielded an instance of
|
17
17
|
# `MatchData`.
|
18
18
|
#
|
19
|
-
# This can be useful in combination with the default_storage plugin.
|
19
|
+
# This can be useful in combination with the `default_storage` plugin.
|
20
20
|
module DynamicStorage
|
21
21
|
module ClassMethods
|
22
22
|
def dynamic_storages
|
data/lib/shrine/plugins/hooks.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
class Shrine
|
2
2
|
module Plugins
|
3
|
-
# The included plugin allows you to hook up to the `.included` hook of the
|
3
|
+
# The `included` plugin allows you to hook up to the `.included` hook of the
|
4
4
|
# attachment module, and call additional methods on the model which includes
|
5
5
|
# it.
|
6
6
|
#
|
@@ -10,9 +10,8 @@ class Shrine
|
|
10
10
|
# end
|
11
11
|
# end
|
12
12
|
#
|
13
|
-
#
|
14
|
-
#
|
15
|
-
# metaprogramming equivalents like `define_method`.
|
13
|
+
# If you want to define additional methods on the model, it's recommended
|
14
|
+
# to use the `module_include` plugin instead.
|
16
15
|
module Included
|
17
16
|
def self.configure(uploader, &block)
|
18
17
|
uploader.opts[:included_block] = block
|
@@ -1,6 +1,6 @@
|
|
1
1
|
class Shrine
|
2
2
|
module Plugins
|
3
|
-
# The keep_files plugin gives you the ability to prevent files from being
|
3
|
+
# The `keep_files` plugin gives you the ability to prevent files from being
|
4
4
|
# deleted. This functionality is useful when implementing soft deletes, or
|
5
5
|
# when implementing some kind of [event store] where you need to track
|
6
6
|
# history.
|
@@ -1,6 +1,6 @@
|
|
1
1
|
class Shrine
|
2
2
|
module Plugins
|
3
|
-
# The moving plugin will *move* files to storages instead of copying them,
|
3
|
+
# The `moving` plugin will *move* files to storages instead of copying them,
|
4
4
|
# when the storage supports it. For FileSystem this will issue a `mv`
|
5
5
|
# command, which is instantaneous regardless of the filesize, so in that
|
6
6
|
# case loading this plugin can significantly speed up the attachment
|
@@ -29,6 +29,7 @@ class Shrine
|
|
29
29
|
end
|
30
30
|
end
|
31
31
|
|
32
|
+
# Generates upload options and calls `#move` on the storage.
|
32
33
|
def move(io, context)
|
33
34
|
location = context[:location]
|
34
35
|
metadata = context[:metadata]
|
@@ -37,14 +38,18 @@ class Shrine
|
|
37
38
|
storage.move(io, location, shrine_metadata: metadata, **upload_options)
|
38
39
|
end
|
39
40
|
|
40
|
-
|
41
|
-
storage.respond_to?(:move) && storage.movable?(io, context[:location])
|
42
|
-
end
|
43
|
-
|
41
|
+
# Returns true if file should be moved and is movable.
|
44
42
|
def move?(io, context)
|
43
|
+
return false if context[:move] == false
|
45
44
|
moving_storage? && movable?(io, context)
|
46
45
|
end
|
47
46
|
|
47
|
+
# Returns true if storage can move this file.
|
48
|
+
def movable?(io, context)
|
49
|
+
storage.respond_to?(:move) && storage.movable?(io, context[:location])
|
50
|
+
end
|
51
|
+
|
52
|
+
# Returns true if file should be moved.
|
48
53
|
def moving_storage?
|
49
54
|
opts[:moving_storages].nil? ||
|
50
55
|
opts[:moving_storages].include?(storage_key)
|
@@ -1,6 +1,6 @@
|
|
1
1
|
class Shrine
|
2
2
|
module Plugins
|
3
|
-
# The multi_delete plugins allows you to leverage your storage's multi
|
3
|
+
# The `multi_delete` plugins allows you to leverage your storage's multi
|
4
4
|
# delete capabilities.
|
5
5
|
#
|
6
6
|
# plugin :multi_delete
|
@@ -11,7 +11,7 @@ class Shrine
|
|
11
11
|
#
|
12
12
|
# Now if you're using Storage::S3, deleting an array of files will issue a
|
13
13
|
# single HTTP request. Some other storages may support multi deletes as
|
14
|
-
# well. The versions plugin uses this plugin for deleting multiple versions
|
14
|
+
# well. The `versions` plugin uses this plugin for deleting multiple versions
|
15
15
|
# at once.
|
16
16
|
module MultiDelete
|
17
17
|
module InstanceMethods
|
@@ -2,8 +2,8 @@ require "thread"
|
|
2
2
|
|
3
3
|
class Shrine
|
4
4
|
module Plugins
|
5
|
-
# The parallelize plugin parallelizes uploads and deletes
|
6
|
-
# versions
|
5
|
+
# The `parallelize` plugin parallelizes uploads and deletes of multiple
|
6
|
+
# versions using threads.
|
7
7
|
#
|
8
8
|
# plugin :parallelize
|
9
9
|
#
|
@@ -1,6 +1,6 @@
|
|
1
1
|
class Shrine
|
2
2
|
module Plugins
|
3
|
-
# The parsed_json plugin is suitable for the case when your framework is
|
3
|
+
# The `parsed_json` plugin is suitable for the case when your framework is
|
4
4
|
# automatically parsing JSON query parameters, allowing you to assign
|
5
5
|
# cached files with hashes/arrays.
|
6
6
|
#
|
@@ -1,25 +1,27 @@
|
|
1
1
|
class Shrine
|
2
2
|
module Plugins
|
3
|
-
# The
|
4
|
-
#
|
3
|
+
# The `processing` plugin allows you to declaratively define file processing
|
4
|
+
# for specified actions.
|
5
5
|
#
|
6
|
-
#
|
7
|
-
# if context[:action] == :store
|
8
|
-
# # ...
|
9
|
-
# end
|
10
|
-
# end
|
11
|
-
#
|
12
|
-
# into
|
6
|
+
# plugin :processing
|
13
7
|
#
|
14
8
|
# process(:store) do |io, context|
|
15
9
|
# # ...
|
16
10
|
# end
|
17
11
|
#
|
12
|
+
# The `io` is the original file, while the `context` contains some
|
13
|
+
# additional information about the upload. The result of the processing
|
14
|
+
# block should be an IO-like object, which will continue being uploaded
|
15
|
+
# instead of the original.
|
16
|
+
#
|
18
17
|
# The declarations are additive and inherited, so for the same action you
|
19
18
|
# can declare multiple blocks, and they will be performed in the same order,
|
20
19
|
# where output from previous will be input to next. You can return `nil`
|
21
20
|
# in any block to signal that no processing was performed and that the
|
22
21
|
# original file should be used.
|
22
|
+
#
|
23
|
+
# If you want the result of processing to be multiple files, use the
|
24
|
+
# `versions` plugin.
|
23
25
|
module Processing
|
24
26
|
def self.configure(uploader)
|
25
27
|
uploader.opts[:processing] = {}
|
@@ -1,6 +1,6 @@
|
|
1
1
|
class Shrine
|
2
2
|
module Plugins
|
3
|
-
# The recache plugin allows you to process your attachment after
|
3
|
+
# The `recache` plugin allows you to process your attachment after
|
4
4
|
# validations succeed, but before the attachment is promoted. This is
|
5
5
|
# useful for example when you want to generate some versions upfront (so
|
6
6
|
# the user immediately sees them) and other versions you want to generate
|
@@ -16,14 +16,24 @@ class Shrine
|
|
16
16
|
# process(:store) do |io, context|
|
17
17
|
# # perform more expensive processing
|
18
18
|
# end
|
19
|
+
#
|
20
|
+
# Recaching will be automatically triggered in a "before save" callback,
|
21
|
+
# but if you're using the attacher directly, you can call it manually:
|
22
|
+
#
|
23
|
+
# attacher.recache if attacher.attached?
|
19
24
|
module Recache
|
20
25
|
module AttacherMethods
|
21
26
|
def save
|
22
|
-
|
23
|
-
_set cache!(get, action: :recache)
|
24
|
-
end
|
27
|
+
recache
|
25
28
|
super
|
26
29
|
end
|
30
|
+
|
31
|
+
def recache
|
32
|
+
if cached?
|
33
|
+
recached = cache!(get, action: :recache)
|
34
|
+
_set(recached)
|
35
|
+
end
|
36
|
+
end
|
27
37
|
end
|
28
38
|
end
|
29
39
|
|
@@ -1,13 +1,13 @@
|
|
1
1
|
class Shrine
|
2
2
|
module Plugins
|
3
|
-
# The remove_attachment plugin allows you to delete attachments through
|
3
|
+
# The `remove_attachment` plugin allows you to delete attachments through
|
4
4
|
# checkboxes on the web form.
|
5
5
|
#
|
6
6
|
# plugin :remove_attachment
|
7
7
|
#
|
8
8
|
# If for example your attachment is called "avatar", this plugin will add
|
9
9
|
# `#remove_avatar` and `#remove_avatar=` methods to your model. This allows
|
10
|
-
# you to easily
|
10
|
+
# you to easily delete attached files through the form:
|
11
11
|
#
|
12
12
|
# <%= form_for @user do |f| %>
|
13
13
|
# <%= f.hidden_field :avatar, value: @user.avatar_data %>
|
@@ -16,8 +16,7 @@ class Shrine
|
|
16
16
|
# <% end %>
|
17
17
|
#
|
18
18
|
# Now when the checkbox is ticked and the form is submitted, the attached
|
19
|
-
# file will be removed.
|
20
|
-
# declared somewhere after the hidden field.
|
19
|
+
# file will be removed.
|
21
20
|
module RemoveAttachment
|
22
21
|
module AttachmentMethods
|
23
22
|
def initialize(*)
|
@@ -1,11 +1,18 @@
|
|
1
1
|
class Shrine
|
2
2
|
module Plugins
|
3
|
-
# The restore_cached_data plugin
|
4
|
-
#
|
5
|
-
#
|
6
|
-
#
|
3
|
+
# The `restore_cached_data` plugin re-extracts cached file's metadata on
|
4
|
+
# assignment. This happens when an uploaded file is retained on validation
|
5
|
+
# errors, or when assigning direct uploaded files. In both cases you
|
6
|
+
# usually want to re-extract metadata on the server side, mainly to prevent
|
7
|
+
# tempering, but also in case of direct uploads to obtain metadata that
|
8
|
+
# couldn't be extracted on the client side.
|
7
9
|
#
|
8
10
|
# plugin :restore_cached_data
|
11
|
+
#
|
12
|
+
# This will give an opened `UploadedFile` for metadata extraction. For
|
13
|
+
# remote storages this will make an HTTP request, and since metadata is
|
14
|
+
# typically found in the beginning of the file, Shrine will download only
|
15
|
+
# the amount of bytes necessary for extracting the metadata.
|
9
16
|
module RestoreCachedData
|
10
17
|
module AttacherMethods
|
11
18
|
private
|
@@ -2,7 +2,7 @@ require "sequel"
|
|
2
2
|
|
3
3
|
class Shrine
|
4
4
|
module Plugins
|
5
|
-
# The sequel plugin extends the "attachment" interface with support for
|
5
|
+
# The `sequel` plugin extends the "attachment" interface with support for
|
6
6
|
# Sequel.
|
7
7
|
#
|
8
8
|
# plugin :sequel
|
@@ -20,7 +20,7 @@ class Shrine
|
|
20
20
|
# you should first disable transactions for those tests.
|
21
21
|
#
|
22
22
|
# If you want to put promoting/deleting into a background job, see the
|
23
|
-
# backgrounding plugin.
|
23
|
+
# `backgrounding` plugin.
|
24
24
|
#
|
25
25
|
# Since attaching first saves the record with a cached attachment, then
|
26
26
|
# saves again with a stored attachment, you can detect this in callbacks:
|
@@ -73,69 +73,58 @@ class Shrine
|
|
73
73
|
|
74
74
|
return unless model < ::Sequel::Model
|
75
75
|
|
76
|
-
|
77
|
-
module_eval <<-RUBY, __FILE__, __LINE__ + 1
|
78
|
-
def validate
|
79
|
-
super
|
80
|
-
#{@name}_attacher.errors.each do |message|
|
81
|
-
errors.add(:#{@name}, message)
|
82
|
-
end
|
83
|
-
end
|
84
|
-
RUBY
|
85
|
-
end
|
76
|
+
opts = shrine_class.opts
|
86
77
|
|
87
|
-
if
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
78
|
+
module_eval <<-RUBY, __FILE__, __LINE__ + 1 if opts[:sequel_validations]
|
79
|
+
def validate
|
80
|
+
super
|
81
|
+
#{@name}_attacher.errors.each do |message|
|
82
|
+
errors.add(:#{@name}, message)
|
92
83
|
end
|
84
|
+
end
|
85
|
+
RUBY
|
93
86
|
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
87
|
+
module_eval <<-RUBY, __FILE__, __LINE__ + 1 if opts[:sequel_callbacks]
|
88
|
+
def before_save
|
89
|
+
super
|
90
|
+
#{@name}_attacher.save if #{@name}_attacher.attached?
|
91
|
+
end
|
98
92
|
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
93
|
+
def after_commit
|
94
|
+
super
|
95
|
+
#{@name}_attacher.finalize if #{@name}_attacher.attached?
|
96
|
+
end
|
97
|
+
|
98
|
+
def after_destroy_commit
|
99
|
+
super
|
100
|
+
#{@name}_attacher.destroy
|
101
|
+
end
|
102
|
+
RUBY
|
105
103
|
end
|
106
104
|
end
|
107
105
|
|
108
106
|
module AttacherClassMethods
|
109
|
-
# Needed by the backgrounding plugin.
|
107
|
+
# Needed by the `backgrounding` plugin.
|
110
108
|
def find_record(record_class, record_id)
|
111
109
|
record_class.with_pk(record_id)
|
112
110
|
end
|
113
111
|
end
|
114
112
|
|
115
113
|
module AttacherMethods
|
116
|
-
private
|
117
|
-
|
118
|
-
# Proceeds with updating the record unless the attachment has changed.
|
119
|
-
def swap(uploaded_file)
|
120
|
-
return if record.send(:"#{name}_data") != record.reload.send(:"#{name}_data")
|
121
|
-
super
|
122
|
-
rescue ::Sequel::NoExistingObject
|
123
|
-
rescue ::Sequel::Error => error
|
124
|
-
raise unless error.message == "Record not found" # prior to version 4.28
|
125
|
-
end
|
126
|
-
|
127
|
-
# Saves the record after assignment, skipping validations.
|
128
|
-
def update(uploaded_file)
|
129
|
-
super
|
130
|
-
record.save(validate: false)
|
131
|
-
end
|
132
|
-
|
133
114
|
# Support for Postgres JSON columns.
|
134
115
|
def read
|
135
116
|
value = super
|
136
117
|
value = value.to_hash if value.respond_to?(:to_hash)
|
137
118
|
value
|
138
119
|
end
|
120
|
+
|
121
|
+
private
|
122
|
+
|
123
|
+
# Saves the record after assignment, skipping validations.
|
124
|
+
def update(uploaded_file)
|
125
|
+
super
|
126
|
+
record.save_changes(validate: false)
|
127
|
+
end
|
139
128
|
end
|
140
129
|
end
|
141
130
|
|