saviour 0.6.2 → 0.6.7
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.
- checksums.yaml +4 -4
- data/.travis.yml +4 -4
- data/README.md +41 -5
- data/gemfiles/5.1.gemfile +0 -2
- data/gemfiles/5.2.gemfile +0 -2
- data/gemfiles/6.0.gemfile +7 -0
- data/lib/saviour.rb +2 -1
- data/lib/saviour/base_uploader.rb +2 -0
- data/lib/saviour/db_helpers.rb +6 -0
- data/lib/saviour/file.rb +10 -10
- data/lib/saviour/integrator.rb +22 -1
- data/lib/saviour/life_cycle.rb +23 -30
- data/lib/saviour/read_only_file.rb +6 -6
- data/lib/saviour/s3_storage.rb +6 -3
- data/lib/saviour/uploader/processors_runner.rb +1 -1
- data/lib/saviour/version.rb +1 -1
- data/saviour.gemspec +2 -2
- data/spec/feature/concurrency_spec.rb +3 -3
- data/spec/feature/crud_workflows_spec.rb +16 -16
- data/spec/feature/dirty_spec.rb +1 -1
- data/spec/feature/halt_processor_spec.rb +1 -1
- data/spec/feature/memory_usage_spec.rb +8 -10
- data/spec/feature/persisted_path_spec.rb +2 -2
- data/spec/feature/processors_api_spec.rb +1 -1
- data/spec/feature/read_only_file_spec.rb +28 -0
- data/spec/feature/reload_model_spec.rb +1 -1
- data/spec/feature/remove_attachment_spec.rb +1 -1
- data/spec/feature/stash_spec.rb +8 -8
- data/spec/feature/storages_spec.rb +87 -0
- data/spec/feature/transactional_behavior_spec.rb +3 -3
- metadata +15 -15
- data/Appraisals +0 -19
- data/spec/feature/storage_overriding_spec.rb +0 -44
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 43509e7e421eab9a8b45159d62c58513dbcb894b0ccecbd96a70cc0a29db74a6
|
4
|
+
data.tar.gz: 91b2eb4cf47dbac1b642c5ccc198ae0040ea0e81ef993c580e894065f1e58ecf
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e4a1fb654e3290d827236f115ebfd93e2f6d4994e57d022dd473f41436365de36182e689d20526cea2c9bb113dd6b558901da5deda945f526242ab2e78e7c633
|
7
|
+
data.tar.gz: 8f3f81305ceb56195d67eb2a6700a5f05bb3e4567c892a983fe845689c952864497e2bd29c47a4256a88a6f003527855952d2ed78e6edc7cff80d66adacca7b0
|
data/.travis.yml
CHANGED
@@ -2,14 +2,14 @@ language: ruby
|
|
2
2
|
sudo: false
|
3
3
|
cache: bundler
|
4
4
|
rvm:
|
5
|
-
- 2.
|
6
|
-
- 2.
|
7
|
-
- 2.
|
8
|
-
- 2.5.0
|
5
|
+
- 2.5.8
|
6
|
+
- 2.6.6
|
7
|
+
- 2.7.1
|
9
8
|
|
10
9
|
gemfile:
|
11
10
|
- gemfiles/5.1.gemfile
|
12
11
|
- gemfiles/5.2.gemfile
|
12
|
+
- gemfiles/6.0.gemfile
|
13
13
|
|
14
14
|
addons:
|
15
15
|
code_climate:
|
data/README.md
CHANGED
@@ -593,7 +593,7 @@ Now, both attachments are independent:
|
|
593
593
|
|
594
594
|
```ruby
|
595
595
|
# `image_thumb` can be changed independently
|
596
|
-
a.
|
596
|
+
a.update! image_thumb: File.open("/path/another_file.png")
|
597
597
|
|
598
598
|
# or removed
|
599
599
|
a.remove_file_thumb!
|
@@ -714,7 +714,7 @@ class ImageUploader < Saviour::BaseUploader
|
|
714
714
|
end
|
715
715
|
|
716
716
|
after_upload do |stash|
|
717
|
-
model.
|
717
|
+
model.update!(size: stash[:size], width: stash[:width], height: stash[:height])
|
718
718
|
end
|
719
719
|
end
|
720
720
|
```
|
@@ -817,11 +817,14 @@ as in the processor's case.
|
|
817
817
|
|
818
818
|
### Introspection
|
819
819
|
|
820
|
-
|
820
|
+
Three methods are added to any class including `Saviour::Model` to give you information about what attachments
|
821
821
|
have been defined in that class.
|
822
822
|
|
823
823
|
`Model.attached_files` will give an array of symbols, representing all the attachments declared in that class.
|
824
824
|
|
825
|
+
`Model.uploader_classes` will give you a hash with all the uploader classes being used in that model, key-ed by
|
826
|
+
the name of each attachment.
|
827
|
+
|
825
828
|
`Model.attached_followers_per_leader` will give a hash where the keys are attachments that have versions
|
826
829
|
assigned, and the values being an array of symbols, representing the attachments that are following that attachment.
|
827
830
|
|
@@ -837,6 +840,7 @@ end
|
|
837
840
|
|
838
841
|
Post.attached_files # => [:image, :image_thumb, :image_thumb_2, :cover]
|
839
842
|
Post.attached_followers_per_leader # => { image: [:image_thumb, :image_thumb_2] }
|
843
|
+
Post.uploader_classes # => { image: SomeUploader, image_thumb: SomeUploader, ... }
|
840
844
|
```
|
841
845
|
|
842
846
|
|
@@ -964,6 +968,38 @@ Any additional information the storage may require can be provided on instance c
|
|
964
968
|
this is not used by Saviour.
|
965
969
|
|
966
970
|
|
971
|
+
### Using `ReadOnlyFile`
|
972
|
+
|
973
|
+
Sometimes you may find the need to have a saviour `File`-like object but you don't have the original model available.
|
974
|
+
|
975
|
+
For example, if you're working directly fetching data from database, you have the `path` to an asset but you're not
|
976
|
+
loading an ActiveRecord object.
|
977
|
+
|
978
|
+
In such cases you can use the class `ReadOnlyFile`, like this:
|
979
|
+
|
980
|
+
```ruby
|
981
|
+
class Product
|
982
|
+
# ...
|
983
|
+
attach_file :image
|
984
|
+
end
|
985
|
+
|
986
|
+
my_cheap_products = ActiveRecord::Base.connection.select_all "select image, ... from products"
|
987
|
+
|
988
|
+
# In this case, you have the path to the assets and want to convert it into an object so that the
|
989
|
+
# rest of the application can work normally with it, you can do:
|
990
|
+
|
991
|
+
storage = Product.uploader_classes[:image].storage
|
992
|
+
file = Saviour::ReadOnlyFile.new(path, storage)
|
993
|
+
|
994
|
+
file.read # -> contents
|
995
|
+
file.public_url # -> url
|
996
|
+
# etc ...
|
997
|
+
```
|
998
|
+
|
999
|
+
You'll need to get the appropriate storage object from the same uploader that attachment is using,
|
1000
|
+
and create a new `ReadOnlyFile` instance only with the asset's path and the storage.
|
1001
|
+
|
1002
|
+
|
967
1003
|
### Bypassing Saviour
|
968
1004
|
|
969
1005
|
The only reference to stored files Saviour holds and uses is the path persisted in the database. If you want to,
|
@@ -1096,7 +1132,7 @@ Then it can be used as:
|
|
1096
1132
|
a = Post.find(42)
|
1097
1133
|
|
1098
1134
|
# Params received from a form
|
1099
|
-
a.
|
1135
|
+
a.update(remove_image: "t")
|
1100
1136
|
```
|
1101
1137
|
|
1102
1138
|
|
@@ -1136,7 +1172,7 @@ The job then should take the model and the attachment to process and run the pro
|
|
1136
1172
|
a = Post.find(42)
|
1137
1173
|
a.image.with_copy do |f|
|
1138
1174
|
# manipulate f as desired
|
1139
|
-
a.
|
1175
|
+
a.update! image: f
|
1140
1176
|
end
|
1141
1177
|
```
|
1142
1178
|
|
data/gemfiles/5.1.gemfile
CHANGED
data/gemfiles/5.2.gemfile
CHANGED
data/lib/saviour.rb
CHANGED
data/lib/saviour/db_helpers.rb
CHANGED
@@ -22,6 +22,9 @@ module Saviour
|
|
22
22
|
def committed!(*)
|
23
23
|
@block.call
|
24
24
|
end
|
25
|
+
|
26
|
+
def trigger_transactional_callbacks?(*)
|
27
|
+
end
|
25
28
|
end
|
26
29
|
|
27
30
|
class RollbackDummy
|
@@ -42,6 +45,9 @@ module Saviour
|
|
42
45
|
|
43
46
|
def committed!(*)
|
44
47
|
end
|
48
|
+
|
49
|
+
def trigger_transactional_callbacks?(*)
|
50
|
+
end
|
45
51
|
end
|
46
52
|
|
47
53
|
|
data/lib/saviour/file.rb
CHANGED
@@ -2,26 +2,26 @@ require 'securerandom'
|
|
2
2
|
|
3
3
|
module Saviour
|
4
4
|
class File
|
5
|
-
attr_reader :persisted_path
|
6
|
-
attr_reader :source
|
5
|
+
attr_reader :persisted_path, :source, :storage
|
7
6
|
|
8
7
|
def initialize(uploader_klass, model, attached_as, persisted_path = nil)
|
9
8
|
@uploader_klass, @model, @attached_as = uploader_klass, model, attached_as
|
10
9
|
@source_was = @source = nil
|
11
10
|
@persisted_path = persisted_path
|
11
|
+
@storage = @uploader_klass.storage
|
12
12
|
|
13
13
|
if persisted_path
|
14
|
-
@model.instance_variable_set("@__uploader_#{@attached_as}_was", ReadOnlyFile.new(persisted_path, @uploader_klass))
|
14
|
+
@model.instance_variable_set("@__uploader_#{@attached_as}_was", ReadOnlyFile.new(persisted_path, @uploader_klass.storage))
|
15
15
|
end
|
16
16
|
end
|
17
17
|
|
18
18
|
def exists?
|
19
|
-
persisted? && @
|
19
|
+
persisted? && @storage.exists?(@persisted_path)
|
20
20
|
end
|
21
21
|
|
22
22
|
def read
|
23
23
|
return nil unless persisted?
|
24
|
-
@
|
24
|
+
@storage.read(@persisted_path)
|
25
25
|
end
|
26
26
|
|
27
27
|
def delete
|
@@ -32,7 +32,7 @@ module Saviour
|
|
32
32
|
|
33
33
|
def public_url
|
34
34
|
return nil unless persisted?
|
35
|
-
@
|
35
|
+
@storage.public_url(@persisted_path)
|
36
36
|
end
|
37
37
|
|
38
38
|
def ==(another_file)
|
@@ -111,7 +111,7 @@ module Saviour
|
|
111
111
|
temp_file.binmode
|
112
112
|
|
113
113
|
begin
|
114
|
-
@
|
114
|
+
@storage.read_to_file(@persisted_path, temp_file)
|
115
115
|
|
116
116
|
yield(temp_file)
|
117
117
|
ensure
|
@@ -154,13 +154,13 @@ module Saviour
|
|
154
154
|
|
155
155
|
case source_type
|
156
156
|
when :stream
|
157
|
-
@
|
157
|
+
@storage.write(contents, path)
|
158
158
|
when :file
|
159
|
-
@
|
159
|
+
@storage.write_from_file(contents, path)
|
160
160
|
end
|
161
161
|
|
162
162
|
@persisted_path = path
|
163
|
-
@model.instance_variable_set("@__uploader_#{@attached_as}_was", ReadOnlyFile.new(persisted_path, @
|
163
|
+
@model.instance_variable_set("@__uploader_#{@attached_as}_was", ReadOnlyFile.new(persisted_path, @storage))
|
164
164
|
path
|
165
165
|
end
|
166
166
|
end
|
data/lib/saviour/integrator.rb
CHANGED
@@ -12,6 +12,8 @@ module Saviour
|
|
12
12
|
@klass.attached_files = []
|
13
13
|
@klass.class_attribute :followers_per_leader_config
|
14
14
|
@klass.followers_per_leader_config = {}
|
15
|
+
@klass.class_attribute :uploader_classes
|
16
|
+
@klass.uploader_classes = {}
|
15
17
|
|
16
18
|
persistence_klass = @persistence_klass
|
17
19
|
|
@@ -36,10 +38,13 @@ module Saviour
|
|
36
38
|
raise ConfigurationError, "you must provide either an UploaderClass or a block to define it."
|
37
39
|
end
|
38
40
|
|
41
|
+
uploader_klass = Class.new(Saviour::BaseUploader, &block) if block
|
42
|
+
|
43
|
+
self.uploader_classes[attach_as] = uploader_klass
|
44
|
+
|
39
45
|
mod = Module.new do
|
40
46
|
define_method(attach_as) do
|
41
47
|
instance_variable_get("@__uploader_#{attach_as}") || begin
|
42
|
-
uploader_klass = Class.new(Saviour::BaseUploader, &block) if block
|
43
48
|
layer = persistence_klass.new(self)
|
44
49
|
new_file = ::Saviour::File.new(uploader_klass, self, attach_as, layer.read(attach_as))
|
45
50
|
|
@@ -79,6 +84,22 @@ module Saviour
|
|
79
84
|
end
|
80
85
|
end
|
81
86
|
|
87
|
+
define_method(:changed) do
|
88
|
+
if ActiveRecord::VERSION::MAJOR == 6 && send("#{attach_as}_changed?")
|
89
|
+
super() + [attach_as.to_s]
|
90
|
+
else
|
91
|
+
super()
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
define_method(:changed?) do
|
96
|
+
if ActiveRecord::VERSION::MAJOR == 6
|
97
|
+
send("#{attach_as}_changed?") || super()
|
98
|
+
else
|
99
|
+
super()
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
82
103
|
define_method("#{attach_as}_change") do
|
83
104
|
[send("#{attach_as}_was"), send(attach_as)]
|
84
105
|
end
|
data/lib/saviour/life_cycle.rb
CHANGED
@@ -1,5 +1,7 @@
|
|
1
1
|
module Saviour
|
2
2
|
class LifeCycle
|
3
|
+
SHOULD_USE_INTERLOCK = defined?(Rails)
|
4
|
+
|
3
5
|
class FileCreator
|
4
6
|
def initialize(current_path, file, column, connection)
|
5
7
|
@file = file
|
@@ -49,7 +51,7 @@ module Saviour
|
|
49
51
|
end
|
50
52
|
|
51
53
|
@new_path = @file.write(
|
52
|
-
|
54
|
+
before_write: ->(path) { dup_file.call if @current_path == path }
|
53
55
|
)
|
54
56
|
|
55
57
|
return unless @new_path
|
@@ -84,26 +86,19 @@ module Saviour
|
|
84
86
|
|
85
87
|
def delete!
|
86
88
|
DbHelpers.run_after_commit do
|
87
|
-
pool = Concurrent::
|
89
|
+
pool = Concurrent::Throttle.new Saviour::Config.concurrent_workers
|
88
90
|
|
89
91
|
futures = attached_files.map do |column|
|
90
|
-
|
91
|
-
file = @model.send(column)
|
92
|
+
pool.future(@model.send(column)) do |file|
|
92
93
|
path = file.persisted_path
|
93
94
|
file.uploader.storage.delete(path) if path
|
94
95
|
file.delete
|
95
|
-
|
96
|
+
end
|
96
97
|
end
|
97
98
|
|
98
99
|
ActiveSupport::Dependencies.interlock.permit_concurrent_loads do
|
99
|
-
futures.each
|
100
|
-
future.value
|
101
|
-
raise(future.reason) if future.rejected?
|
102
|
-
end
|
100
|
+
futures.each(&:value!)
|
103
101
|
end
|
104
|
-
|
105
|
-
pool.shutdown
|
106
|
-
pool.wait_for_termination
|
107
102
|
end
|
108
103
|
end
|
109
104
|
|
@@ -124,34 +119,32 @@ module Saviour
|
|
124
119
|
next unless @model.send(column).changed?
|
125
120
|
|
126
121
|
klass.new(
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
122
|
+
persistence_layer.read(column),
|
123
|
+
@model.send(column),
|
124
|
+
column,
|
125
|
+
ActiveRecord::Base.connection
|
131
126
|
)
|
132
127
|
end.compact
|
133
128
|
|
134
|
-
pool = Concurrent::
|
129
|
+
pool = Concurrent::Throttle.new Saviour::Config.concurrent_workers
|
130
|
+
|
135
131
|
futures = uploaders.map { |uploader|
|
136
|
-
|
137
|
-
if
|
138
|
-
Rails.application.executor.wrap {
|
132
|
+
pool.future(uploader) { |given_uploader|
|
133
|
+
if SHOULD_USE_INTERLOCK
|
134
|
+
Rails.application.executor.wrap { given_uploader.upload }
|
139
135
|
else
|
140
|
-
|
136
|
+
given_uploader.upload
|
141
137
|
end
|
142
138
|
}
|
143
139
|
}
|
144
140
|
|
145
|
-
|
146
|
-
futures.map do |x|
|
147
|
-
x.value.tap do
|
148
|
-
raise(x.reason) if x.rejected?
|
149
|
-
end
|
150
|
-
end.compact
|
151
|
-
end
|
141
|
+
work = -> { futures.map(&:value!).compact }
|
152
142
|
|
153
|
-
|
154
|
-
|
143
|
+
result = if SHOULD_USE_INTERLOCK
|
144
|
+
ActiveSupport::Dependencies.interlock.permit_concurrent_loads(&work)
|
145
|
+
else
|
146
|
+
work.call
|
147
|
+
end
|
155
148
|
|
156
149
|
attrs = result.to_h
|
157
150
|
|
@@ -1,24 +1,24 @@
|
|
1
1
|
module Saviour
|
2
2
|
class ReadOnlyFile
|
3
|
-
attr_reader :persisted_path
|
3
|
+
attr_reader :persisted_path, :storage
|
4
4
|
|
5
|
-
def initialize(persisted_path,
|
5
|
+
def initialize(persisted_path, storage)
|
6
6
|
@persisted_path = persisted_path
|
7
|
-
@
|
7
|
+
@storage = storage
|
8
8
|
end
|
9
9
|
|
10
10
|
def exists?
|
11
|
-
persisted? &&
|
11
|
+
persisted? && @storage.exists?(@persisted_path)
|
12
12
|
end
|
13
13
|
|
14
14
|
def read
|
15
15
|
return nil unless persisted?
|
16
|
-
@
|
16
|
+
@storage.read(@persisted_path)
|
17
17
|
end
|
18
18
|
|
19
19
|
def public_url
|
20
20
|
return nil unless persisted?
|
21
|
-
@
|
21
|
+
@storage.public_url(@persisted_path)
|
22
22
|
end
|
23
23
|
alias_method :url, :public_url
|
24
24
|
|
data/lib/saviour/s3_storage.rb
CHANGED
@@ -11,6 +11,7 @@ module Saviour
|
|
11
11
|
def initialize(conf = {})
|
12
12
|
@bucket = conf.delete(:bucket)
|
13
13
|
@public_url_prefix = conf.delete(:public_url_prefix)
|
14
|
+
@extra_aws_client_options = conf.delete(:aws_client_opts)
|
14
15
|
@conf = conf
|
15
16
|
@create_options = conf.delete(:create_options) { {} }
|
16
17
|
conf.fetch(:aws_access_key_id) { raise(ArgumentError, "aws_access_key_id is required") }
|
@@ -119,9 +120,11 @@ module Saviour
|
|
119
120
|
|
120
121
|
def client
|
121
122
|
@client ||= Aws::S3::Client.new(
|
122
|
-
|
123
|
-
|
124
|
-
|
123
|
+
{
|
124
|
+
access_key_id: @conf[:aws_access_key_id],
|
125
|
+
secret_access_key: @conf[:aws_secret_access_key],
|
126
|
+
region: @region
|
127
|
+
}.merge(@extra_aws_client_options || {})
|
125
128
|
)
|
126
129
|
end
|
127
130
|
end
|
data/lib/saviour/version.rb
CHANGED
data/saviour.gemspec
CHANGED
@@ -13,17 +13,17 @@ Gem::Specification.new do |spec|
|
|
13
13
|
spec.files = `git ls-files`.split($/)
|
14
14
|
spec.require_paths = ["lib"]
|
15
15
|
|
16
|
-
spec.required_ruby_version = ">= 2.
|
16
|
+
spec.required_ruby_version = ">= 2.5.0"
|
17
17
|
|
18
18
|
spec.add_dependency "activerecord", ">= 5.1"
|
19
19
|
spec.add_dependency "activesupport", ">= 5.1"
|
20
20
|
spec.add_dependency "concurrent-ruby", ">= 1.0.5"
|
21
|
+
spec.add_dependency "concurrent-ruby-edge", ">= 0.6.0"
|
21
22
|
|
22
23
|
spec.add_development_dependency "bundler"
|
23
24
|
spec.add_development_dependency "rspec"
|
24
25
|
spec.add_development_dependency "rake"
|
25
26
|
spec.add_development_dependency "sqlite3"
|
26
|
-
spec.add_development_dependency "appraisal"
|
27
27
|
spec.add_development_dependency "aws-sdk-s3"
|
28
28
|
spec.add_development_dependency "mime-types"
|
29
29
|
spec.add_development_dependency "get_process_mem"
|
@@ -52,7 +52,7 @@ describe "concurrency on operations" do
|
|
52
52
|
|
53
53
|
Saviour::Config.concurrent_workers = 4
|
54
54
|
|
55
|
-
a.
|
55
|
+
a.update! file: Saviour::StringSource.new("contents", "file.txt"),
|
56
56
|
file_thumb: Saviour::StringSource.new("contents", "file_2.txt"),
|
57
57
|
file_thumb_2: Saviour::StringSource.new("contents", "file_3.txt"),
|
58
58
|
file_thumb_3: Saviour::StringSource.new("contents", "file_4.txt")
|
@@ -66,7 +66,7 @@ describe "concurrency on operations" do
|
|
66
66
|
|
67
67
|
Saviour::Config.concurrent_workers = 1
|
68
68
|
|
69
|
-
a.
|
69
|
+
a.update! file: Saviour::StringSource.new("contents", "file.txt"),
|
70
70
|
file_thumb: Saviour::StringSource.new("contents", "file_2.txt"),
|
71
71
|
file_thumb_2: Saviour::StringSource.new("contents", "file_3.txt"),
|
72
72
|
file_thumb_3: Saviour::StringSource.new("contents", "file_4.txt")
|
@@ -80,7 +80,7 @@ describe "concurrency on operations" do
|
|
80
80
|
|
81
81
|
Saviour::Config.concurrent_workers = 2
|
82
82
|
|
83
|
-
a.
|
83
|
+
a.update! file: Saviour::StringSource.new("contents", "file.txt"),
|
84
84
|
file_thumb: Saviour::StringSource.new("contents", "file_2.txt"),
|
85
85
|
file_thumb_2: Saviour::StringSource.new("contents", "file_3.txt"),
|
86
86
|
file_thumb_3: Saviour::StringSource.new("contents", "file_4.txt")
|
@@ -19,14 +19,14 @@ describe "CRUD" do
|
|
19
19
|
it do
|
20
20
|
with_test_file("example.xml") do |example|
|
21
21
|
a = klass.create!
|
22
|
-
expect(a.
|
22
|
+
expect(a.update(file: example)).to be_truthy
|
23
23
|
end
|
24
24
|
end
|
25
25
|
|
26
26
|
it do
|
27
27
|
with_test_file("example.xml") do |example|
|
28
28
|
a = klass.create!
|
29
|
-
a.
|
29
|
+
a.update(file: example)
|
30
30
|
|
31
31
|
expect(Saviour::Config.storage.exists?(a[:file])).to be_truthy
|
32
32
|
end
|
@@ -35,7 +35,7 @@ describe "CRUD" do
|
|
35
35
|
it do
|
36
36
|
with_test_file("example.xml") do |example, real_filename|
|
37
37
|
a = klass.create!
|
38
|
-
a.
|
38
|
+
a.update(file: example)
|
39
39
|
expect(a[:file]).to eq "/store/dir/#{real_filename}"
|
40
40
|
end
|
41
41
|
end
|
@@ -43,7 +43,7 @@ describe "CRUD" do
|
|
43
43
|
it do
|
44
44
|
with_test_file("example.xml") do |example|
|
45
45
|
a = klass.create!
|
46
|
-
a.
|
46
|
+
a.update(file: example)
|
47
47
|
|
48
48
|
example.rewind
|
49
49
|
expect(a.file.read).to eq example.read
|
@@ -53,7 +53,7 @@ describe "CRUD" do
|
|
53
53
|
it do
|
54
54
|
with_test_file("example.xml") do |example|
|
55
55
|
a = klass.create!
|
56
|
-
a.
|
56
|
+
a.update(file: example)
|
57
57
|
|
58
58
|
expect(a.file.exists?).to be_truthy
|
59
59
|
end
|
@@ -62,7 +62,7 @@ describe "CRUD" do
|
|
62
62
|
it do
|
63
63
|
with_test_file("example.xml") do |example, real_filename|
|
64
64
|
a = klass.create!
|
65
|
-
a.
|
65
|
+
a.update(file: example)
|
66
66
|
|
67
67
|
expect(a.file.filename).to eq real_filename
|
68
68
|
end
|
@@ -71,7 +71,7 @@ describe "CRUD" do
|
|
71
71
|
it do
|
72
72
|
with_test_file("example.xml") do |example, real_filename|
|
73
73
|
a = klass.create!
|
74
|
-
a.
|
74
|
+
a.update(file: example)
|
75
75
|
|
76
76
|
expect(a.file.url).to eq "http://domain.com/store/dir/#{real_filename}"
|
77
77
|
expect(a.file.public_url).to eq a.file.url
|
@@ -137,7 +137,7 @@ describe "CRUD" do
|
|
137
137
|
it do
|
138
138
|
with_test_file("example.xml") do |example|
|
139
139
|
a = klass.create!
|
140
|
-
a.
|
140
|
+
a.update(file: example)
|
141
141
|
expect(a.file.exists?).to be_truthy
|
142
142
|
expect(a.destroy).to be_truthy
|
143
143
|
|
@@ -150,13 +150,13 @@ describe "CRUD" do
|
|
150
150
|
it do
|
151
151
|
with_test_file("example.xml") do |example|
|
152
152
|
a = klass.create!
|
153
|
-
a.
|
153
|
+
a.update(file: example)
|
154
154
|
|
155
155
|
expect(Saviour::Config.storage.exists?(a[:file])).to be_truthy
|
156
156
|
previous_location = a[:file]
|
157
157
|
|
158
158
|
with_test_file("camaloon.jpg") do |example_2|
|
159
|
-
a.
|
159
|
+
a.update(file: example_2)
|
160
160
|
expect(Saviour::Config.storage.exists?(a[:file])).to be_truthy
|
161
161
|
|
162
162
|
expect(Saviour::Config.storage.exists?(previous_location)).to be_falsey
|
@@ -167,7 +167,7 @@ describe "CRUD" do
|
|
167
167
|
it "does allow to update the same file to another contents in the same path" do
|
168
168
|
a = klass.create! file: Saviour::StringSource.new("contents", "file.txt")
|
169
169
|
|
170
|
-
a.
|
170
|
+
a.update! file: Saviour::StringSource.new("foo", "file.txt")
|
171
171
|
expect(Saviour::Config.storage.read(a[:file])).to eq "foo"
|
172
172
|
end
|
173
173
|
|
@@ -175,7 +175,7 @@ describe "CRUD" do
|
|
175
175
|
a = klass.create!
|
176
176
|
|
177
177
|
expect_to_yield_queries(count: 1) do
|
178
|
-
a.
|
178
|
+
a.update! file: Saviour::StringSource.new("foo", "file.txt")
|
179
179
|
end
|
180
180
|
end
|
181
181
|
|
@@ -183,7 +183,7 @@ describe "CRUD" do
|
|
183
183
|
a = klass.create!
|
184
184
|
|
185
185
|
expect_to_yield_queries(count: 2) do
|
186
|
-
a.
|
186
|
+
a.update! name: "Text",
|
187
187
|
file: Saviour::StringSource.new("foo", "file.txt")
|
188
188
|
end
|
189
189
|
end
|
@@ -192,7 +192,7 @@ describe "CRUD" do
|
|
192
192
|
it "touches updated_at if the model has it" do
|
193
193
|
time = Time.now - 4.years
|
194
194
|
a = klass.create! updated_at: time
|
195
|
-
a.
|
195
|
+
a.update! file: Saviour::StringSource.new("foo", "file.txt")
|
196
196
|
|
197
197
|
expect(a.updated_at).to be > time + 2.years
|
198
198
|
end
|
@@ -207,7 +207,7 @@ describe "CRUD" do
|
|
207
207
|
it "works with models that do not have updated_at" do
|
208
208
|
a = klass.create!
|
209
209
|
expect(a).not_to respond_to(:updated_at)
|
210
|
-
a.
|
210
|
+
a.update! file: Saviour::StringSource.new("foo", "file.txt")
|
211
211
|
expect(a.file.read).to eq "foo"
|
212
212
|
end
|
213
213
|
end
|
@@ -226,7 +226,7 @@ describe "CRUD" do
|
|
226
226
|
|
227
227
|
expected_query = %Q{UPDATE "tests" SET "file" = '/store/dir/file.txt', "file_thumb" = '/store/dir/file.txt'}
|
228
228
|
expect_to_yield_queries(count: 1, including: [expected_query]) do
|
229
|
-
a.
|
229
|
+
a.update!(
|
230
230
|
file: Saviour::StringSource.new("foo", "file.txt"),
|
231
231
|
file_thumb: Saviour::StringSource.new("foo", "file.txt")
|
232
232
|
)
|
data/spec/feature/dirty_spec.rb
CHANGED
@@ -23,7 +23,7 @@ describe "halt processor behavior" do
|
|
23
23
|
|
24
24
|
expect(Saviour::Config.storage).to_not receive(:write)
|
25
25
|
|
26
|
-
a.
|
26
|
+
a.update! file: StringIO.new("contents")
|
27
27
|
expect(a.reload.read_attribute(:file)).to be_nil
|
28
28
|
end
|
29
29
|
|
@@ -9,8 +9,6 @@ describe "memory usage" do
|
|
9
9
|
a
|
10
10
|
}
|
11
11
|
|
12
|
-
CHUNK = ("A" * 1024).freeze
|
13
|
-
|
14
12
|
let(:size_to_test) { 10 } # Test with 10Mb files
|
15
13
|
|
16
14
|
def with_tempfile
|
@@ -18,7 +16,7 @@ describe "memory usage" do
|
|
18
16
|
|
19
17
|
size_to_test.times do
|
20
18
|
1024.times do
|
21
|
-
f.write
|
19
|
+
f.write SecureRandom.hex(512)
|
22
20
|
end
|
23
21
|
end
|
24
22
|
f.flush
|
@@ -56,7 +54,7 @@ describe "memory usage" do
|
|
56
54
|
with_no_gc do
|
57
55
|
base_line = GetProcessMem.new.mb
|
58
56
|
|
59
|
-
a.
|
57
|
+
a.update! file: f
|
60
58
|
|
61
59
|
# Expect memory usage to grow below 10% of the file size
|
62
60
|
expect(GetProcessMem.new.mb - base_line).to be < size_to_test / 10
|
@@ -72,22 +70,22 @@ describe "memory usage" do
|
|
72
70
|
|
73
71
|
process do |contents, filename|
|
74
72
|
digest = Digest::MD5.hexdigest(contents)
|
73
|
+
|
75
74
|
[contents, "#{digest}-#{filename}"]
|
76
75
|
end
|
77
76
|
}
|
78
77
|
}
|
79
78
|
|
80
79
|
it do
|
81
|
-
a = base_klass.create!
|
82
|
-
|
83
80
|
with_tempfile do |f|
|
84
81
|
with_no_gc do
|
85
|
-
|
82
|
+
a = base_klass.create!
|
86
83
|
|
87
|
-
|
84
|
+
base_line = GetProcessMem.new.mb
|
88
85
|
|
89
|
-
|
90
|
-
|
86
|
+
a.update! file: f
|
87
|
+
# Expect memory usage to grow at least half the file size
|
88
|
+
expect(GetProcessMem.new.mb - base_line).to be >= size_to_test / 2
|
91
89
|
end
|
92
90
|
end
|
93
91
|
end
|
@@ -11,7 +11,7 @@ describe "persisted path" do
|
|
11
11
|
|
12
12
|
with_test_file("example.xml") do |example|
|
13
13
|
a = klass.create!
|
14
|
-
expect(a.
|
14
|
+
expect(a.update(file: example)).to be_truthy
|
15
15
|
expect(Saviour::Config.storage.exists?(a[:file])).to be_truthy
|
16
16
|
expect(File.dirname(a[:file])).to eq "/store/dir"
|
17
17
|
|
@@ -20,7 +20,7 @@ describe "persisted path" do
|
|
20
20
|
|
21
21
|
with_test_file("camaloon.jpg") do |example_2|
|
22
22
|
b = klass.create!
|
23
|
-
expect(b.
|
23
|
+
expect(b.update(file: example_2)).to be_truthy
|
24
24
|
|
25
25
|
expect(Saviour::Config.storage.exists?(b[:file])).to be_truthy
|
26
26
|
expect(Saviour::Config.storage.exists?(a[:file])).to be_truthy
|
@@ -88,7 +88,7 @@ describe "processor's API" do
|
|
88
88
|
a = klass.create!
|
89
89
|
|
90
90
|
expect {
|
91
|
-
a.
|
91
|
+
a.update! file: Saviour::StringSource.new("contents", "filename.txt")
|
92
92
|
}.to raise_error.with_message("custom problem!")
|
93
93
|
end
|
94
94
|
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe "direct usage of ReadOnlyFile" do
|
4
|
+
before { allow(Saviour::Config).to receive(:storage).and_return(Saviour::LocalStorage.new(local_prefix: @tmpdir, public_url_prefix: "http://domain.com")) }
|
5
|
+
|
6
|
+
let(:uploader) {
|
7
|
+
Class.new(Saviour::BaseUploader) do
|
8
|
+
store_dir { "/store/dir" }
|
9
|
+
end
|
10
|
+
}
|
11
|
+
|
12
|
+
let(:klass) {
|
13
|
+
klass = Class.new(Test) { include Saviour::Model }
|
14
|
+
klass.attach_file :file, uploader
|
15
|
+
klass
|
16
|
+
}
|
17
|
+
|
18
|
+
it "can be created" do
|
19
|
+
a = klass.create! file: Saviour::StringSource.new("contents", "file.txt")
|
20
|
+
|
21
|
+
path = a[:file]
|
22
|
+
|
23
|
+
read_only_file = Saviour::ReadOnlyFile.new(path, klass.uploader_classes[:file].storage)
|
24
|
+
|
25
|
+
expect(read_only_file.read).to eq "contents"
|
26
|
+
expect(read_only_file.public_url).to eq "http://domain.com/store/dir/file.txt"
|
27
|
+
end
|
28
|
+
end
|
@@ -116,7 +116,7 @@ describe "remove attachment" do
|
|
116
116
|
expect(Saviour::Config.storage.exists?(path)).to be_truthy
|
117
117
|
expect(Saviour::Config.storage.read(path)).to eq "Some contents"
|
118
118
|
|
119
|
-
a.
|
119
|
+
a.update!(file: Saviour::StringSource.new("Other contents", "filename.txt"))
|
120
120
|
expect(a.file.persisted?).to be_truthy
|
121
121
|
expect(a.file.read).to eq "Other contents"
|
122
122
|
expect(Saviour::Config.storage.exists?(path)).to be_truthy
|
data/spec/feature/stash_spec.rb
CHANGED
@@ -14,7 +14,7 @@ describe "stash data on process" do
|
|
14
14
|
end
|
15
15
|
|
16
16
|
after_upload do |stash|
|
17
|
-
model.
|
17
|
+
model.update!(file_size: stash[:file_size])
|
18
18
|
end
|
19
19
|
}
|
20
20
|
|
@@ -23,7 +23,7 @@ describe "stash data on process" do
|
|
23
23
|
|
24
24
|
a = klass.create!
|
25
25
|
|
26
|
-
a.
|
26
|
+
a.update! file: Saviour::StringSource.new("a" * 74, "file.txt")
|
27
27
|
expect(a.file_size).to eq 74
|
28
28
|
end
|
29
29
|
|
@@ -38,7 +38,7 @@ describe "stash data on process" do
|
|
38
38
|
end
|
39
39
|
|
40
40
|
after_upload do |stash|
|
41
|
-
model.
|
41
|
+
model.update!(file_size: stash[:file_size])
|
42
42
|
end
|
43
43
|
}
|
44
44
|
|
@@ -61,7 +61,7 @@ describe "stash data on process" do
|
|
61
61
|
end
|
62
62
|
|
63
63
|
after_upload do |stash|
|
64
|
-
model.
|
64
|
+
model.update!("size_#{attached_as}" => stash[:size])
|
65
65
|
end
|
66
66
|
}
|
67
67
|
|
@@ -74,7 +74,7 @@ describe "stash data on process" do
|
|
74
74
|
# - 2 queries to update size
|
75
75
|
# - 1 query to assign stored paths
|
76
76
|
expect_to_yield_queries(count: 3) do
|
77
|
-
a.
|
77
|
+
a.update! file: Saviour::StringSource.new("a" * 74, "file.txt"),
|
78
78
|
file_thumb: Saviour::StringSource.new("a" * 31, "file_2.txt")
|
79
79
|
end
|
80
80
|
|
@@ -99,7 +99,7 @@ describe "stash data on process" do
|
|
99
99
|
end
|
100
100
|
|
101
101
|
after_upload do |stash|
|
102
|
-
model.
|
102
|
+
model.update!(stash[:model])
|
103
103
|
end
|
104
104
|
}
|
105
105
|
|
@@ -123,11 +123,11 @@ describe "stash data on process" do
|
|
123
123
|
end
|
124
124
|
|
125
125
|
after_upload do |stash|
|
126
|
-
model.
|
126
|
+
model.update!(file_size: stash[:file_size])
|
127
127
|
end
|
128
128
|
|
129
129
|
after_upload do |stash|
|
130
|
-
model.
|
130
|
+
model.update!(name: stash[:name])
|
131
131
|
end
|
132
132
|
}
|
133
133
|
|
@@ -0,0 +1,87 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe "uploader declaration" do
|
4
|
+
let!(:default_storage) do
|
5
|
+
Saviour::LocalStorage.new(
|
6
|
+
local_prefix: @tmpdir,
|
7
|
+
public_url_prefix: "http://domain.com"
|
8
|
+
)
|
9
|
+
end
|
10
|
+
|
11
|
+
let!(:another_storage) do
|
12
|
+
Saviour::LocalStorage.new(
|
13
|
+
local_prefix: @tmpdir,
|
14
|
+
public_url_prefix: "http://custom-domain.com"
|
15
|
+
)
|
16
|
+
end
|
17
|
+
|
18
|
+
before { allow(Saviour::Config).to receive(:storage).and_return(default_storage) }
|
19
|
+
|
20
|
+
it "lets you override storage on attachment basis" do
|
21
|
+
klass = Class.new(Test) { include Saviour::Model }
|
22
|
+
custom_storage = another_storage
|
23
|
+
|
24
|
+
klass.attach_file(:file) do
|
25
|
+
store_dir { "/store/dir" }
|
26
|
+
end
|
27
|
+
|
28
|
+
klass.attach_file(:file_thumb) do
|
29
|
+
store_dir { "/store/dir" }
|
30
|
+
with_storage custom_storage
|
31
|
+
end
|
32
|
+
|
33
|
+
a = klass.create!(
|
34
|
+
file: Saviour::StringSource.new("content", "houhou.txt"),
|
35
|
+
file_thumb: Saviour::StringSource.new("content", "custom_houhou.txt")
|
36
|
+
)
|
37
|
+
|
38
|
+
expect(a.file.filename).to eq "houhou.txt"
|
39
|
+
expect(a.file.url).to eq 'http://domain.com/store/dir/houhou.txt'
|
40
|
+
|
41
|
+
expect(a.file_thumb.filename).to eq "custom_houhou.txt"
|
42
|
+
expect(a.file_thumb.url).to eq 'http://custom-domain.com/store/dir/custom_houhou.txt'
|
43
|
+
end
|
44
|
+
|
45
|
+
context do
|
46
|
+
it "allows for lambda storages" do
|
47
|
+
allow(Saviour::Config).to receive(:storage).and_return(-> { default_storage })
|
48
|
+
|
49
|
+
klass = Class.new(Test) { include Saviour::Model }
|
50
|
+
|
51
|
+
klass.attach_file(:file) do
|
52
|
+
store_dir { "/store/dir" }
|
53
|
+
end
|
54
|
+
|
55
|
+
a = klass.create!(file: Saviour::StringSource.new("content", "houhou.txt"))
|
56
|
+
|
57
|
+
expect(a.file.filename).to eq "houhou.txt"
|
58
|
+
expect(a.file.url).to eq 'http://domain.com/store/dir/houhou.txt'
|
59
|
+
end
|
60
|
+
|
61
|
+
it "allow to change storage on the fly" do
|
62
|
+
dynamic_storage = default_storage
|
63
|
+
allow(Saviour::Config).to receive(:storage).and_return(-> { dynamic_storage })
|
64
|
+
|
65
|
+
klass = Class.new(Test) { include Saviour::Model }
|
66
|
+
|
67
|
+
klass.attach_file(:file) do
|
68
|
+
store_dir { "/store/dir" }
|
69
|
+
end
|
70
|
+
|
71
|
+
a = klass.create!(
|
72
|
+
file: Saviour::StringSource.new("content", "houhou.txt"),
|
73
|
+
file_thumb: Saviour::StringSource.new("content", "custom_houhou.txt")
|
74
|
+
)
|
75
|
+
|
76
|
+
expect(a.file.filename).to eq "houhou.txt"
|
77
|
+
expect(a.file.url).to eq 'http://domain.com/store/dir/houhou.txt'
|
78
|
+
|
79
|
+
dynamic_storage = another_storage # Lambda will pick up the new storage.
|
80
|
+
|
81
|
+
a = klass.create!(file: Saviour::StringSource.new("content", "houhou.txt"))
|
82
|
+
|
83
|
+
expect(a.file.filename).to eq "houhou.txt"
|
84
|
+
expect(a.file.url).to eq 'http://custom-domain.com/store/dir/houhou.txt'
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
@@ -87,7 +87,7 @@ describe "transactional behavior" do
|
|
87
87
|
|
88
88
|
with_test_file("camaloon.jpg") do |file2|
|
89
89
|
ActiveRecord::Base.transaction do
|
90
|
-
a.
|
90
|
+
a.update! file: file2
|
91
91
|
|
92
92
|
expect(Saviour::Config.storage.exists?(path1)).to be_truthy
|
93
93
|
expect(Saviour::Config.storage.exists?(a[:file])).to be_truthy
|
@@ -107,7 +107,7 @@ describe "transactional behavior" do
|
|
107
107
|
|
108
108
|
with_test_file("camaloon.jpg") do |file2|
|
109
109
|
ActiveRecord::Base.transaction do
|
110
|
-
a.
|
110
|
+
a.update! file: file2
|
111
111
|
path2 = a[:file]
|
112
112
|
|
113
113
|
expect(Saviour::Config.storage.exists?(path1)).to be_truthy
|
@@ -135,7 +135,7 @@ describe "transactional behavior" do
|
|
135
135
|
expect(Saviour::Config.storage.read(a[:file])).to eq "original content"
|
136
136
|
|
137
137
|
ActiveRecord::Base.transaction do
|
138
|
-
a.
|
138
|
+
a.update! file: Saviour::StringSource.new("new content", "file.txt")
|
139
139
|
expect(Saviour::Config.storage.read(a[:file])).to eq "new content"
|
140
140
|
raise ActiveRecord::Rollback
|
141
141
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: saviour
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.6.
|
4
|
+
version: 0.6.7
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Roger Campos
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2020-06-05 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activerecord
|
@@ -53,21 +53,21 @@ dependencies:
|
|
53
53
|
- !ruby/object:Gem::Version
|
54
54
|
version: 1.0.5
|
55
55
|
- !ruby/object:Gem::Dependency
|
56
|
-
name:
|
56
|
+
name: concurrent-ruby-edge
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
58
58
|
requirements:
|
59
59
|
- - ">="
|
60
60
|
- !ruby/object:Gem::Version
|
61
|
-
version:
|
62
|
-
type: :
|
61
|
+
version: 0.6.0
|
62
|
+
type: :runtime
|
63
63
|
prerelease: false
|
64
64
|
version_requirements: !ruby/object:Gem::Requirement
|
65
65
|
requirements:
|
66
66
|
- - ">="
|
67
67
|
- !ruby/object:Gem::Version
|
68
|
-
version:
|
68
|
+
version: 0.6.0
|
69
69
|
- !ruby/object:Gem::Dependency
|
70
|
-
name:
|
70
|
+
name: bundler
|
71
71
|
requirement: !ruby/object:Gem::Requirement
|
72
72
|
requirements:
|
73
73
|
- - ">="
|
@@ -81,7 +81,7 @@ dependencies:
|
|
81
81
|
- !ruby/object:Gem::Version
|
82
82
|
version: '0'
|
83
83
|
- !ruby/object:Gem::Dependency
|
84
|
-
name:
|
84
|
+
name: rspec
|
85
85
|
requirement: !ruby/object:Gem::Requirement
|
86
86
|
requirements:
|
87
87
|
- - ">="
|
@@ -95,7 +95,7 @@ dependencies:
|
|
95
95
|
- !ruby/object:Gem::Version
|
96
96
|
version: '0'
|
97
97
|
- !ruby/object:Gem::Dependency
|
98
|
-
name:
|
98
|
+
name: rake
|
99
99
|
requirement: !ruby/object:Gem::Requirement
|
100
100
|
requirements:
|
101
101
|
- - ">="
|
@@ -109,7 +109,7 @@ dependencies:
|
|
109
109
|
- !ruby/object:Gem::Version
|
110
110
|
version: '0'
|
111
111
|
- !ruby/object:Gem::Dependency
|
112
|
-
name:
|
112
|
+
name: sqlite3
|
113
113
|
requirement: !ruby/object:Gem::Requirement
|
114
114
|
requirements:
|
115
115
|
- - ">="
|
@@ -173,13 +173,13 @@ extra_rdoc_files: []
|
|
173
173
|
files:
|
174
174
|
- ".gitignore"
|
175
175
|
- ".travis.yml"
|
176
|
-
- Appraisals
|
177
176
|
- Gemfile
|
178
177
|
- LICENSE.txt
|
179
178
|
- README.md
|
180
179
|
- Rakefile
|
181
180
|
- gemfiles/5.1.gemfile
|
182
181
|
- gemfiles/5.2.gemfile
|
182
|
+
- gemfiles/6.0.gemfile
|
183
183
|
- lib/saviour.rb
|
184
184
|
- lib/saviour/base_uploader.rb
|
185
185
|
- lib/saviour/config.rb
|
@@ -211,12 +211,13 @@ files:
|
|
211
211
|
- spec/feature/original_assigned_file_is_not_modified_spec.rb
|
212
212
|
- spec/feature/persisted_path_spec.rb
|
213
213
|
- spec/feature/processors_api_spec.rb
|
214
|
+
- spec/feature/read_only_file_spec.rb
|
214
215
|
- spec/feature/reload_model_spec.rb
|
215
216
|
- spec/feature/remove_attachment_spec.rb
|
216
217
|
- spec/feature/reopens_file_at_every_process_spec.rb
|
217
218
|
- spec/feature/rewind_source_before_read_spec.rb
|
218
219
|
- spec/feature/stash_spec.rb
|
219
|
-
- spec/feature/
|
220
|
+
- spec/feature/storages_spec.rb
|
220
221
|
- spec/feature/transactional_behavior_spec.rb
|
221
222
|
- spec/feature/uploader_declaration_spec.rb
|
222
223
|
- spec/feature/validations_spec.rb
|
@@ -247,15 +248,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
247
248
|
requirements:
|
248
249
|
- - ">="
|
249
250
|
- !ruby/object:Gem::Version
|
250
|
-
version: 2.
|
251
|
+
version: 2.5.0
|
251
252
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
252
253
|
requirements:
|
253
254
|
- - ">="
|
254
255
|
- !ruby/object:Gem::Version
|
255
256
|
version: '0'
|
256
257
|
requirements: []
|
257
|
-
|
258
|
-
rubygems_version: 2.7.6
|
258
|
+
rubygems_version: 3.0.3
|
259
259
|
signing_key:
|
260
260
|
specification_version: 4
|
261
261
|
summary: File storage handler following active record model lifecycle
|
data/Appraisals
DELETED
@@ -1,19 +0,0 @@
|
|
1
|
-
appraise "4.0" do
|
2
|
-
gem "activesupport", "~> 4.0.0"
|
3
|
-
gem "activerecord", "~> 4.0.0"
|
4
|
-
end
|
5
|
-
|
6
|
-
appraise "4.1" do
|
7
|
-
gem "activesupport", "~> 4.1.0"
|
8
|
-
gem "activerecord", "~> 4.1.0"
|
9
|
-
end
|
10
|
-
|
11
|
-
appraise "4.2" do
|
12
|
-
gem "activesupport", "~> 4.2.0"
|
13
|
-
gem "activerecord", "~> 4.2.0"
|
14
|
-
end
|
15
|
-
|
16
|
-
appraise "5.0" do
|
17
|
-
gem "activesupport", "~> 5.0.0"
|
18
|
-
gem "activerecord", "~> 5.0.0"
|
19
|
-
end
|
@@ -1,44 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
describe "uploader declaration" do
|
4
|
-
let!(:default_storage) do
|
5
|
-
Saviour::LocalStorage.new(
|
6
|
-
local_prefix: @tmpdir,
|
7
|
-
public_url_prefix: "http://domain.com"
|
8
|
-
)
|
9
|
-
end
|
10
|
-
|
11
|
-
let!(:custom_storage) do
|
12
|
-
Saviour::LocalStorage.new(
|
13
|
-
local_prefix: @tmpdir,
|
14
|
-
public_url_prefix: "http://custom-domain.com"
|
15
|
-
)
|
16
|
-
end
|
17
|
-
|
18
|
-
before { allow(Saviour::Config).to receive(:storage).and_return(default_storage) }
|
19
|
-
|
20
|
-
it "lets you override storage on attachment basis" do
|
21
|
-
klass = Class.new(Test) { include Saviour::Model }
|
22
|
-
kustom_storage = custom_storage
|
23
|
-
|
24
|
-
klass.attach_file(:file) do
|
25
|
-
store_dir { "/store/dir" }
|
26
|
-
end
|
27
|
-
|
28
|
-
klass.attach_file(:file_thumb) do
|
29
|
-
store_dir { "/store/dir" }
|
30
|
-
with_storage kustom_storage
|
31
|
-
end
|
32
|
-
|
33
|
-
a = klass.create!(
|
34
|
-
file: Saviour::StringSource.new("content", "houhou.txt"),
|
35
|
-
file_thumb: Saviour::StringSource.new("content", "custom_houhou.txt")
|
36
|
-
)
|
37
|
-
|
38
|
-
expect(a.file.filename).to eq "houhou.txt"
|
39
|
-
expect(a.file.url).to eq 'http://domain.com/store/dir/houhou.txt'
|
40
|
-
|
41
|
-
expect(a.file_thumb.filename).to eq "custom_houhou.txt"
|
42
|
-
expect(a.file_thumb.url).to eq 'http://custom-domain.com/store/dir/custom_houhou.txt'
|
43
|
-
end
|
44
|
-
end
|