saviour 0.2.3 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +2 -1
- data/.travis.yml +4 -13
- data/DECOMPOSE.md +66 -0
- data/Gemfile +1 -0
- data/README.md +39 -8
- data/lib/saviour/attribute_name_calculator.rb +15 -0
- data/lib/saviour/base_integrator.rb +53 -0
- data/lib/saviour/basic_model.rb +7 -0
- data/lib/saviour/config.rb +0 -1
- data/lib/saviour/file.rb +13 -34
- data/lib/saviour/life_cycle.rb +57 -0
- data/lib/saviour/source_filename_extractor.rb +21 -0
- data/lib/saviour/url_source.rb +1 -1
- data/lib/saviour/utils/class_attribute.rb +26 -0
- data/lib/saviour/version.rb +1 -1
- data/lib/saviour.rb +7 -155
- data/saviour.gemspec +1 -5
- data/spec/feature/access_to_model_and_mounted_as_spec.rb +13 -5
- data/spec/feature/versions_spec.rb +72 -49
- data/spec/models/attribute_name_calculator_spec.rb +11 -0
- data/spec/models/basic_model_spec.rb +51 -0
- data/spec/models/file_spec.rb +32 -55
- data/spec/models/url_source_spec.rb +5 -5
- data/spec/spec_helper.rb +2 -30
- data/spec/support/models.rb +7 -2
- metadata +12 -72
- data/Appraisals +0 -19
- data/gemfiles/4.0.gemfile +0 -9
- data/gemfiles/4.1.gemfile +0 -9
- data/gemfiles/4.2.gemfile +0 -9
- data/gemfiles/5.0.gemfile +0 -9
- data/lib/saviour/processors/digest.rb +0 -16
- data/spec/feature/crud_workflows_spec.rb +0 -143
- data/spec/feature/persisted_path_spec.rb +0 -34
- data/spec/feature/reload_model_spec.rb +0 -24
- data/spec/feature/validations_spec.rb +0 -171
- data/spec/models/processors/digest_spec.rb +0 -22
- data/spec/models/saviour_spec.rb +0 -80
- data/spec/support/schema.rb +0 -9
data/lib/saviour.rb
CHANGED
@@ -1,11 +1,7 @@
|
|
1
1
|
require 'fileutils'
|
2
|
-
require 'digest/md5'
|
3
|
-
require 'active_support/concern'
|
4
|
-
require 'active_support/core_ext'
|
5
|
-
require 'active_support/core_ext/module/attribute_accessors'
|
6
2
|
require 'fog/aws'
|
7
3
|
|
8
|
-
require 'saviour/
|
4
|
+
require 'saviour/utils/class_attribute'
|
9
5
|
|
10
6
|
require 'saviour/version'
|
11
7
|
require 'saviour/base_uploader'
|
@@ -15,156 +11,12 @@ require 'saviour/s3_storage'
|
|
15
11
|
require 'saviour/config'
|
16
12
|
require 'saviour/string_source'
|
17
13
|
require 'saviour/url_source'
|
14
|
+
require 'saviour/basic_model'
|
15
|
+
require 'saviour/base_integrator'
|
16
|
+
require 'saviour/attribute_name_calculator'
|
17
|
+
require 'saviour/source_filename_extractor'
|
18
|
+
require 'saviour/life_cycle'
|
18
19
|
|
19
|
-
module Saviour
|
20
|
-
class ColumnNamer
|
21
|
-
def initialize(attached_as, version = nil)
|
22
|
-
@attached_as, @version = attached_as, version
|
23
|
-
end
|
24
|
-
|
25
|
-
def name
|
26
|
-
if @version
|
27
|
-
"#{@attached_as}_#{@version}"
|
28
|
-
else
|
29
|
-
@attached_as.to_s
|
30
|
-
end
|
31
|
-
end
|
32
|
-
end
|
33
|
-
|
34
|
-
class ModelHooks
|
35
|
-
def initialize(model)
|
36
|
-
@model = model
|
37
|
-
end
|
38
|
-
|
39
|
-
def delete!
|
40
|
-
attached_files.each do |column, versions|
|
41
|
-
(versions + [nil]).each { |version| @model.send(column, version).delete if @model.send(column, version).exists? }
|
42
|
-
end
|
43
|
-
end
|
44
|
-
|
45
|
-
def save!
|
46
|
-
attached_files.each do |column, versions|
|
47
|
-
base_file_changed = @model.send(column).changed?
|
48
|
-
original_content = @model.send(column).source_data if base_file_changed
|
49
|
-
|
50
|
-
versions.each do |version|
|
51
|
-
if @model.send(column, version).changed?
|
52
|
-
upload_file(column, version)
|
53
|
-
elsif base_file_changed
|
54
|
-
@model.send(column, version).assign(StringSource.new(original_content, default_version_filename(column, version)))
|
55
|
-
upload_file(column, version)
|
56
|
-
end
|
57
|
-
end
|
58
|
-
|
59
|
-
upload_file(column, nil) if base_file_changed
|
60
|
-
end
|
61
|
-
end
|
62
|
-
|
63
|
-
def validate!
|
64
|
-
validations.each do |column, method_or_blocks|
|
65
|
-
(attached_files[column] + [nil]).each do |version|
|
66
|
-
if @model.send(column, version).changed?
|
67
|
-
method_or_blocks.each { |method_or_block| run_validation(column, version, method_or_block) }
|
68
|
-
end
|
69
|
-
end
|
70
|
-
end
|
71
|
-
end
|
72
|
-
|
73
|
-
def default_version_filename(column, version)
|
74
|
-
filename = @model.send(column).filename_to_be_assigned
|
75
|
-
"#{::File.basename(filename, ".*")}_#{version}#{::File.extname(filename)}"
|
76
|
-
end
|
77
|
-
|
78
|
-
def upload_file(column, version)
|
79
|
-
name = ColumnNamer.new(column, version).name
|
80
|
-
Config.storage.delete(@model.read_attribute(name)) if @model.read_attribute(name)
|
81
|
-
new_path = @model.send(column, version).write
|
82
|
-
@model.update_column(name, new_path)
|
83
|
-
end
|
84
|
-
|
85
|
-
def attached_files
|
86
|
-
@model.class.attached_files || {}
|
87
|
-
end
|
88
|
-
|
89
|
-
def run_validation(column, version, method_or_block)
|
90
|
-
data = @model.send(column, version).source_data
|
91
|
-
filename = @model.send(column, version).filename_to_be_assigned
|
92
|
-
opts = {attached_as: column, version: version}
|
93
|
-
|
94
|
-
if method_or_block.respond_to?(:call)
|
95
|
-
if method_or_block.arity == 2
|
96
|
-
@model.instance_exec(data, filename, &method_or_block)
|
97
|
-
else
|
98
|
-
@model.instance_exec(data, filename, opts, &method_or_block)
|
99
|
-
end
|
100
|
-
else
|
101
|
-
if @model.method(method_or_block).arity == 2
|
102
|
-
@model.send(method_or_block, data, filename)
|
103
|
-
else
|
104
|
-
@model.send(method_or_block, data, filename, opts)
|
105
|
-
end
|
106
|
-
end
|
107
|
-
end
|
108
|
-
|
109
|
-
def validations
|
110
|
-
@model.class.__saviour_validations || {}
|
111
|
-
end
|
112
|
-
end
|
113
20
|
|
114
|
-
|
115
|
-
|
116
|
-
NoActiveRecordDetected = Class.new(StandardError)
|
117
|
-
|
118
|
-
included do
|
119
|
-
raise(NoActiveRecordDetected, "Error: ActiveRecord not detected in #{self}") unless self.ancestors.include?(ActiveRecord::Base)
|
120
|
-
|
121
|
-
class_attribute(:attached_files, :__saviour_validations)
|
122
|
-
|
123
|
-
after_destroy { ModelHooks.new(self).delete! }
|
124
|
-
after_save { ModelHooks.new(self).save! }
|
125
|
-
validate { ModelHooks.new(self).validate! }
|
126
|
-
end
|
127
|
-
|
128
|
-
def reload
|
129
|
-
self.class.attached_files.each do |attach_as, versions|
|
130
|
-
(versions + [nil]).each { |version| instance_variable_set("@__uploader_#{version}_#{attach_as}", nil) }
|
131
|
-
end
|
132
|
-
super
|
133
|
-
end
|
134
|
-
|
135
|
-
module ClassMethods
|
136
|
-
def attach_file(attach_as, uploader_klass)
|
137
|
-
self.attached_files ||= {}
|
138
|
-
versions = uploader_klass.versions || []
|
139
|
-
|
140
|
-
([nil] + versions).each do |version|
|
141
|
-
column_name = ColumnNamer.new(attach_as, version).name
|
142
|
-
|
143
|
-
if self.table_exists? && !self.column_names.include?(column_name.to_s)
|
144
|
-
raise RuntimeError, "#{self} must have a database string column named '#{column_name}'"
|
145
|
-
end
|
146
|
-
end
|
147
|
-
|
148
|
-
define_method(attach_as) do |version = nil|
|
149
|
-
instance_variable_get("@__uploader_#{version}_#{attach_as}") ||
|
150
|
-
instance_variable_set("@__uploader_#{version}_#{attach_as}", ::Saviour::File.new(uploader_klass, self, attach_as, version))
|
151
|
-
end
|
152
|
-
|
153
|
-
define_method("#{attach_as}=") do |value|
|
154
|
-
send(attach_as).assign(value)
|
155
|
-
end
|
156
|
-
|
157
|
-
define_method("#{attach_as}_changed?") do
|
158
|
-
send(attach_as).changed?
|
159
|
-
end
|
160
|
-
|
161
|
-
self.attached_files[attach_as] ||= []
|
162
|
-
self.attached_files[attach_as] += versions
|
163
|
-
end
|
164
|
-
|
165
|
-
def attach_validation(attach_as, method_name = nil, &block)
|
166
|
-
self.__saviour_validations ||= Hash.new { [] }
|
167
|
-
self.__saviour_validations[attach_as] += [method_name || block]
|
168
|
-
end
|
169
|
-
end
|
21
|
+
module Saviour
|
170
22
|
end
|
data/saviour.gemspec
CHANGED
@@ -13,15 +13,11 @@ 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.1.0"
|
17
17
|
|
18
|
-
spec.add_dependency "activerecord", ">= 4.0"
|
19
|
-
spec.add_dependency "activesupport", ">= 4.0"
|
20
18
|
spec.add_dependency "fog-aws"
|
21
19
|
spec.add_dependency "mime-types"
|
22
20
|
spec.add_development_dependency "bundler"
|
23
21
|
spec.add_development_dependency "rake"
|
24
22
|
spec.add_development_dependency "rspec"
|
25
|
-
spec.add_development_dependency "sqlite3"
|
26
|
-
spec.add_development_dependency "appraisal"
|
27
23
|
end
|
@@ -11,7 +11,13 @@ describe "access to model data from uploaders" do
|
|
11
11
|
}
|
12
12
|
|
13
13
|
let(:klass) {
|
14
|
-
klass = Class.new
|
14
|
+
klass = Class.new {
|
15
|
+
include Saviour::BasicModel
|
16
|
+
|
17
|
+
def id
|
18
|
+
87
|
19
|
+
end
|
20
|
+
}
|
15
21
|
klass.attach_file :file, uploader
|
16
22
|
klass
|
17
23
|
}
|
@@ -19,10 +25,12 @@ describe "access to model data from uploaders" do
|
|
19
25
|
describe "file store" do
|
20
26
|
it do
|
21
27
|
with_test_file("example.xml") do |example, name|
|
22
|
-
a = klass.
|
23
|
-
|
24
|
-
|
25
|
-
|
28
|
+
a = klass.new
|
29
|
+
a.file = example
|
30
|
+
path = a.file.write
|
31
|
+
|
32
|
+
expect(Saviour::Config.storage.exists?(path)).to be_truthy
|
33
|
+
expect(path).to eq "/store/dir/87/87-file-#{name}"
|
26
34
|
end
|
27
35
|
end
|
28
36
|
end
|
@@ -14,7 +14,7 @@ describe "saving a new file" do
|
|
14
14
|
}
|
15
15
|
|
16
16
|
let(:klass) {
|
17
|
-
a = Class.new
|
17
|
+
a = Class.new { include Saviour::BasicModel }
|
18
18
|
a.attach_file :file, uploader
|
19
19
|
a
|
20
20
|
}
|
@@ -22,9 +22,13 @@ describe "saving a new file" do
|
|
22
22
|
describe "creation following main file" do
|
23
23
|
it do
|
24
24
|
with_test_file("example.xml") do |example|
|
25
|
-
a = klass.
|
26
|
-
|
27
|
-
|
25
|
+
a = klass.new
|
26
|
+
a.file = example
|
27
|
+
Saviour::LifeCycle.new(a).save!
|
28
|
+
|
29
|
+
path = a.file(:thumb).persisted_path
|
30
|
+
expect(path).not_to be_nil
|
31
|
+
expect(Saviour::Config.storage.exists?(path)).to be_truthy
|
28
32
|
end
|
29
33
|
end
|
30
34
|
end
|
@@ -32,14 +36,16 @@ describe "saving a new file" do
|
|
32
36
|
describe "deletion" do
|
33
37
|
it do
|
34
38
|
with_test_file("example.xml") do |example|
|
35
|
-
a = klass.
|
36
|
-
a.
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
a.
|
41
|
-
|
42
|
-
|
39
|
+
a = klass.new
|
40
|
+
a.file = example
|
41
|
+
Saviour::LifeCycle.new(a).save!
|
42
|
+
|
43
|
+
expect(Saviour::Config.storage.exists?(a.file(:thumb).persisted_path)).to be_truthy
|
44
|
+
expect(Saviour::Config.storage.exists?(a.file.persisted_path)).to be_truthy
|
45
|
+
|
46
|
+
Saviour::LifeCycle.new(a).delete!
|
47
|
+
expect(Saviour::Config.storage.exists?(a.file(:thumb).persisted_path)).to be_falsey
|
48
|
+
expect(Saviour::Config.storage.exists?(a.file.persisted_path)).to be_falsey
|
43
49
|
end
|
44
50
|
end
|
45
51
|
end
|
@@ -47,13 +53,18 @@ describe "saving a new file" do
|
|
47
53
|
describe "changes following main file" do
|
48
54
|
it do
|
49
55
|
with_test_file("example.xml") do |example|
|
50
|
-
a = klass.
|
51
|
-
|
52
|
-
|
56
|
+
a = klass.new
|
57
|
+
a.file = example
|
58
|
+
Saviour::LifeCycle.new(a).save!
|
59
|
+
path = a.file(:thumb).persisted_path
|
60
|
+
expect(Saviour::Config.storage.exists?(path)).to be_truthy
|
53
61
|
|
54
62
|
with_test_file("camaloon.jpg") do |file|
|
55
|
-
a.
|
56
|
-
|
63
|
+
a.file = file
|
64
|
+
Saviour::LifeCycle.new(a).save!
|
65
|
+
path = a.file(:thumb).persisted_path
|
66
|
+
|
67
|
+
expect(Saviour::Config.storage.exists?(path)).to be_truthy
|
57
68
|
file.rewind
|
58
69
|
expect(a.file(:thumb).read).to eq file.read
|
59
70
|
end
|
@@ -75,8 +86,9 @@ describe "saving a new file" do
|
|
75
86
|
|
76
87
|
it "#url" do
|
77
88
|
with_test_file("example.xml") do |example, name|
|
78
|
-
a = klass.
|
79
|
-
|
89
|
+
a = klass.new
|
90
|
+
a.file = example
|
91
|
+
Saviour::LifeCycle.new(a).save!
|
80
92
|
|
81
93
|
versioned_name = "#{File.basename(name, ".*")}_thumb#{File.extname(name)}"
|
82
94
|
expect(a.file(:thumb).url).to eq "http://domain.com/versions/store/dir/#{versioned_name}"
|
@@ -85,8 +97,9 @@ describe "saving a new file" do
|
|
85
97
|
|
86
98
|
it "#read" do
|
87
99
|
with_test_file("text.txt") do |example|
|
88
|
-
a = klass.
|
89
|
-
a.
|
100
|
+
a = klass.new
|
101
|
+
a.file = example
|
102
|
+
Saviour::LifeCycle.new(a).save!
|
90
103
|
|
91
104
|
expect(a.file(:thumb).read).to eq "Hello world\n_for_version_thumb"
|
92
105
|
end
|
@@ -94,21 +107,24 @@ describe "saving a new file" do
|
|
94
107
|
|
95
108
|
it "#delete" do
|
96
109
|
with_test_file("example.xml") do |example|
|
97
|
-
a = klass.
|
98
|
-
|
99
|
-
|
100
|
-
expect(Saviour::Config.storage.exists?(a
|
110
|
+
a = klass.new
|
111
|
+
a.file = example
|
112
|
+
Saviour::LifeCycle.new(a).save!
|
113
|
+
expect(Saviour::Config.storage.exists?(a.file(:thumb).persisted_path)).to be_truthy
|
114
|
+
expect(Saviour::Config.storage.exists?(a.file.persisted_path)).to be_truthy
|
101
115
|
|
102
116
|
a.file(:thumb).delete
|
103
|
-
|
104
|
-
expect(Saviour::Config.storage.exists?(a
|
117
|
+
|
118
|
+
expect(Saviour::Config.storage.exists?(a.file(:thumb).persisted_path)).to be_falsey
|
119
|
+
expect(Saviour::Config.storage.exists?(a.file.persisted_path)).to be_truthy
|
105
120
|
end
|
106
121
|
end
|
107
122
|
|
108
123
|
it "#exists?" do
|
109
124
|
with_test_file("example.xml") do |example|
|
110
|
-
a = klass.
|
111
|
-
|
125
|
+
a = klass.new
|
126
|
+
a.file = example
|
127
|
+
Saviour::LifeCycle.new(a).save!
|
112
128
|
expect(a.file(:thumb).exists?).to be_truthy
|
113
129
|
end
|
114
130
|
end
|
@@ -117,18 +133,21 @@ describe "saving a new file" do
|
|
117
133
|
describe "assign specific version after first creation" do
|
118
134
|
it do
|
119
135
|
with_test_file("example.xml") do |example|
|
120
|
-
a = klass.
|
121
|
-
|
122
|
-
|
123
|
-
|
136
|
+
a = klass.new
|
137
|
+
a.file = example
|
138
|
+
Saviour::LifeCycle.new(a).save!
|
139
|
+
|
140
|
+
thumb_path = a.file(:thumb).persisted_path
|
141
|
+
expect(Saviour::Config.storage.exists?(thumb_path)).to be_truthy
|
142
|
+
expect(thumb_path).to eq "/versions/store/dir/#{File.basename(example, ".*")}_thumb.xml"
|
124
143
|
|
125
144
|
with_test_file("camaloon.jpg") do |ex2, filename|
|
126
145
|
a.file(:thumb).assign(ex2)
|
146
|
+
Saviour::LifeCycle.new(a).save!
|
147
|
+
thumb_path = a.file(:thumb).persisted_path
|
127
148
|
|
128
|
-
expect(
|
129
|
-
|
130
|
-
expect(Saviour::Config.storage.exists?(a[:file_thumb])).to be_truthy
|
131
|
-
expect(a[:file_thumb]).to eq "/versions/store/dir/#{File.basename(filename, ".*")}.jpg"
|
149
|
+
expect(Saviour::Config.storage.exists?(thumb_path)).to be_truthy
|
150
|
+
expect(thumb_path).to eq "/versions/store/dir/#{File.basename(filename, ".*")}.jpg"
|
132
151
|
end
|
133
152
|
end
|
134
153
|
end
|
@@ -147,19 +166,23 @@ describe "saving a new file" do
|
|
147
166
|
|
148
167
|
it "runs the processors for that version only" do
|
149
168
|
with_test_file("example.xml") do |example|
|
150
|
-
a = klass.
|
151
|
-
|
152
|
-
|
153
|
-
|
169
|
+
a = klass.new
|
170
|
+
a.file = example
|
171
|
+
Saviour::LifeCycle.new(a).save!
|
172
|
+
thumb_path = a.file(:thumb).persisted_path
|
173
|
+
|
174
|
+
expect(Saviour::Config.storage.exists?(thumb_path)).to be_truthy
|
175
|
+
expect(thumb_path).to eq "/versions/store/dir/#{File.basename(example, ".*")}_thumb.xml"
|
154
176
|
|
155
177
|
with_test_file("camaloon.jpg") do |ex2, filename|
|
156
178
|
a.file(:thumb).assign(ex2)
|
157
179
|
|
158
|
-
|
180
|
+
Saviour::LifeCycle.new(a).save!
|
181
|
+
thumb_path = a.file(:thumb).persisted_path
|
159
182
|
|
160
|
-
expect(Saviour::Config.storage.exists?(
|
161
|
-
expect(
|
162
|
-
expect(Saviour::Config.storage.read(
|
183
|
+
expect(Saviour::Config.storage.exists?(thumb_path)).to be_truthy
|
184
|
+
expect(thumb_path).to eq "/versions/store/dir/#{File.basename(filename, ".*")}.jpg"
|
185
|
+
expect(Saviour::Config.storage.read(thumb_path)).to eq "modified_content"
|
163
186
|
end
|
164
187
|
end
|
165
188
|
end
|
@@ -168,16 +191,16 @@ describe "saving a new file" do
|
|
168
191
|
|
169
192
|
describe "respects version assignation vs main file assignation on conflict" do
|
170
193
|
it do
|
171
|
-
a = klass.
|
194
|
+
a = klass.new
|
172
195
|
|
173
196
|
with_test_file("example.xml") do |file1, fname1|
|
174
197
|
with_test_file("camaloon.jpg") do |file2, fname2|
|
175
198
|
a.file.assign(file1)
|
176
199
|
a.file(:thumb).assign(file2)
|
177
|
-
a.save!
|
200
|
+
Saviour::LifeCycle.new(a).save!
|
178
201
|
|
179
|
-
expect(a
|
180
|
-
expect(a
|
202
|
+
expect(a.file.persisted_path).to eq "/store/dir/#{fname1}"
|
203
|
+
expect(a.file(:thumb).persisted_path).to eq "/versions/store/dir/#{fname2}"
|
181
204
|
end
|
182
205
|
end
|
183
206
|
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Saviour::AttributeNameCalculator do
|
4
|
+
it "returns the attached_as value" do
|
5
|
+
expect(Saviour::AttributeNameCalculator.new("preview_file").name).to eq "preview_file"
|
6
|
+
end
|
7
|
+
|
8
|
+
it "appends the version if provided" do
|
9
|
+
expect(Saviour::AttributeNameCalculator.new("preview_file", "thumb").name).to eq "preview_file_thumb"
|
10
|
+
end
|
11
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Saviour do
|
4
|
+
describe ".attached_files" do
|
5
|
+
it "includes a mapping of the currently attached files and their versions" do
|
6
|
+
uploader = Class.new(Saviour::BaseUploader) do
|
7
|
+
store_dir { "/store/dir" }
|
8
|
+
|
9
|
+
version(:thumb)
|
10
|
+
version(:thumb_2)
|
11
|
+
end
|
12
|
+
|
13
|
+
klass = Class.new do
|
14
|
+
include Saviour::BasicModel
|
15
|
+
attach_file :file, uploader
|
16
|
+
end
|
17
|
+
|
18
|
+
expect(klass.attached_files).to eq({file: [:thumb, :thumb_2]})
|
19
|
+
|
20
|
+
klass2 = Class.new do
|
21
|
+
include Saviour::BasicModel
|
22
|
+
attach_file :file, Saviour::BaseUploader
|
23
|
+
end
|
24
|
+
|
25
|
+
expect(klass2.attached_files).to eq({file: []})
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
it "doens't mess with default File constant" do
|
30
|
+
# Constant lookup in ruby works by lexical scope, so we can't create classes dynamically like above.
|
31
|
+
expect(TestForSaviourFileResolution.new.foo).to be_falsey
|
32
|
+
end
|
33
|
+
|
34
|
+
it "shares model definitions with subclasses" do
|
35
|
+
uploader = Class.new(Saviour::BaseUploader) do
|
36
|
+
store_dir { "/store/dir" }
|
37
|
+
version(:thumb)
|
38
|
+
end
|
39
|
+
|
40
|
+
klass = Class.new do
|
41
|
+
include Saviour::BasicModel
|
42
|
+
attach_file :file, uploader
|
43
|
+
end
|
44
|
+
expect(klass.attached_files).to eq({file: [:thumb]})
|
45
|
+
|
46
|
+
klass2 = Class.new(klass)
|
47
|
+
expect(klass2.attached_files).to eq({file: [:thumb]})
|
48
|
+
|
49
|
+
expect(klass2.new.file).to respond_to :exists?
|
50
|
+
end
|
51
|
+
end
|