carrierwave 0.1
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of carrierwave might be problematic. Click here for more details.
- data/Generators +4 -0
- data/LICENSE +20 -0
- data/README.md +242 -0
- data/Rakefile +96 -0
- data/TODO +0 -0
- data/lib/carrierwave.rb +67 -0
- data/lib/carrierwave/mount.rb +153 -0
- data/lib/carrierwave/orm/activerecord.rb +20 -0
- data/lib/carrierwave/orm/datamapper.rb +20 -0
- data/lib/carrierwave/processing/image_science.rb +70 -0
- data/lib/carrierwave/processing/rmagick.rb +161 -0
- data/lib/carrierwave/sanitized_file.rb +242 -0
- data/lib/carrierwave/storage/abstract.rb +80 -0
- data/lib/carrierwave/storage/file.rb +40 -0
- data/lib/carrierwave/storage/s3.rb +83 -0
- data/lib/carrierwave/uploader.rb +427 -0
- data/lib/generators/uploader_generator.rb +20 -0
- data/rails_generators/uploader/USAGE +2 -0
- data/rails_generators/uploader/templates/uploader.rb +33 -0
- data/rails_generators/uploader/uploader_generator.rb +19 -0
- data/spec/fixtures/bork.txt +1 -0
- data/spec/fixtures/test.jpeg +1 -0
- data/spec/fixtures/test.jpg +1 -0
- data/spec/mount_spec.rb +181 -0
- data/spec/orm/activerecord_spec.rb +168 -0
- data/spec/orm/datamapper_spec.rb +133 -0
- data/spec/sanitized_file_spec.rb +624 -0
- data/spec/spec_helper.rb +120 -0
- data/spec/uploader_spec.rb +739 -0
- metadata +92 -0
@@ -0,0 +1,80 @@
|
|
1
|
+
module CarrierWave
|
2
|
+
module Storage
|
3
|
+
##
|
4
|
+
# This file serves mostly as a specification for Storage engines. There is no requirement
|
5
|
+
# that storage engines must be a subclass of this class. However, any storage engine must
|
6
|
+
# conform to the following interface:
|
7
|
+
#
|
8
|
+
# The storage engine must respond to store!, taking an uploader object and a
|
9
|
+
# CarrierWave::SanitizedFile as parameters. This method should do something to store
|
10
|
+
# the given file, and then return an object.
|
11
|
+
#
|
12
|
+
# The storage engine must respond to retrieve!, taking an uploader object and an identifier
|
13
|
+
# as parameters. This method should do retrieve and then return an object.
|
14
|
+
#
|
15
|
+
# The objects returned by store! and retrieve! both *must* respond to +identifier+, taking
|
16
|
+
# no arguments. Identifier is a string that uniquely identifies this file and can be used
|
17
|
+
# to retrieve it later.
|
18
|
+
#
|
19
|
+
class Abstract
|
20
|
+
|
21
|
+
##
|
22
|
+
# Do setup specific for this storage engine
|
23
|
+
#
|
24
|
+
def self.setup!; end
|
25
|
+
|
26
|
+
##
|
27
|
+
# Do something to store the file
|
28
|
+
#
|
29
|
+
# @param [CarrierWave::Uploader] uploader an uploader object
|
30
|
+
# @param [CarrierWave::SanitizedFile] file the file to store
|
31
|
+
#
|
32
|
+
# @return [#identifier] an object
|
33
|
+
#
|
34
|
+
def self.store!(uploader, file)
|
35
|
+
self.new
|
36
|
+
end
|
37
|
+
|
38
|
+
# Do something to retrieve the file
|
39
|
+
#
|
40
|
+
# @param [CarrierWave::Uploader] uploader an uploader object
|
41
|
+
# @param [String] identifier uniquely identifies the file
|
42
|
+
#
|
43
|
+
# @return [#identifier] an object
|
44
|
+
#
|
45
|
+
def self.retrieve!(uploader, identifier)
|
46
|
+
self.new
|
47
|
+
end
|
48
|
+
|
49
|
+
##
|
50
|
+
# Should return a String that uniquely identifies this file and can be used to retrieve it from
|
51
|
+
# the same storage engine later on.
|
52
|
+
#
|
53
|
+
# This is OPTIONAL
|
54
|
+
#
|
55
|
+
# @return [String] path to the file
|
56
|
+
#
|
57
|
+
def identifier; end
|
58
|
+
|
59
|
+
##
|
60
|
+
# Should return the url where the file is publically accessible. If this is not set, then
|
61
|
+
# it is assumed that the url is the path relative to the public directory.
|
62
|
+
#
|
63
|
+
# This is OPTIONAL
|
64
|
+
#
|
65
|
+
# @return [String] file's url
|
66
|
+
#
|
67
|
+
def url; end
|
68
|
+
|
69
|
+
##
|
70
|
+
# Should return the path where the file is corrently located. This is OPTIONAL.
|
71
|
+
#
|
72
|
+
# This is OPTIONAL
|
73
|
+
#
|
74
|
+
# @return [String] path to the file
|
75
|
+
#
|
76
|
+
def path; end
|
77
|
+
|
78
|
+
end # Abstract
|
79
|
+
end # Storage
|
80
|
+
end # CarrierWave
|
@@ -0,0 +1,40 @@
|
|
1
|
+
module CarrierWave
|
2
|
+
module Storage
|
3
|
+
class File < Abstract
|
4
|
+
|
5
|
+
def initialize(uploader)
|
6
|
+
@uploader = uploader
|
7
|
+
end
|
8
|
+
|
9
|
+
##
|
10
|
+
# Move the file to the uploader's store path.
|
11
|
+
#
|
12
|
+
# @param [CarrierWave::Uploader] uploader an uploader object
|
13
|
+
# @param [CarrierWave::SanitizedFile] file the file to store
|
14
|
+
#
|
15
|
+
# @return [CarrierWave::SanitizedFile] a sanitized file
|
16
|
+
#
|
17
|
+
def self.store!(uploader, file)
|
18
|
+
path = ::File.join(uploader.store_dir, uploader.filename)
|
19
|
+
path = ::File.expand_path(path, uploader.public)
|
20
|
+
file.move_to(path)
|
21
|
+
file
|
22
|
+
end
|
23
|
+
|
24
|
+
##
|
25
|
+
# Retrieve the file from its store path
|
26
|
+
#
|
27
|
+
# @param [CarrierWave::Uploader] uploader an uploader object
|
28
|
+
# @param [String] identifier the filename of the file
|
29
|
+
#
|
30
|
+
# @return [CarrierWave::SanitizedFile] a sanitized file
|
31
|
+
#
|
32
|
+
def self.retrieve!(uploader, identifier)
|
33
|
+
path = ::File.join(uploader.store_dir, identifier)
|
34
|
+
path = ::File.expand_path(path, uploader.public)
|
35
|
+
CarrierWave::SanitizedFile.new(path)
|
36
|
+
end
|
37
|
+
|
38
|
+
end # File
|
39
|
+
end # Storage
|
40
|
+
end # CarrierWave
|
@@ -0,0 +1,83 @@
|
|
1
|
+
module CarrierWave
|
2
|
+
module Storage
|
3
|
+
##
|
4
|
+
# Uploads things to Amazon S3 webservices
|
5
|
+
#
|
6
|
+
class S3 < Abstract
|
7
|
+
|
8
|
+
def initialize(bucket, store_dir, identifier)
|
9
|
+
@bucket = bucket
|
10
|
+
@store_dir = store_dir
|
11
|
+
@identifier = identifier
|
12
|
+
end
|
13
|
+
|
14
|
+
##
|
15
|
+
# Connect to Amazon S3
|
16
|
+
#
|
17
|
+
def self.setup!
|
18
|
+
require 'aws/s3'
|
19
|
+
AWS::S3::Base.establish_connection!(
|
20
|
+
:access_key_id => CarrierWave.config[:s3][:access_key_id],
|
21
|
+
:secret_access_key => CarrierWave.config[:s3][:secret_access_key]
|
22
|
+
)
|
23
|
+
end
|
24
|
+
|
25
|
+
##
|
26
|
+
# @return [String] the bucket set in the config options
|
27
|
+
#
|
28
|
+
def self.bucket
|
29
|
+
CarrierWave.config[:s3][:bucket]
|
30
|
+
end
|
31
|
+
|
32
|
+
##
|
33
|
+
# @return [Symbol] the access priviliges the uploaded files should have
|
34
|
+
#
|
35
|
+
def self.access
|
36
|
+
CarrierWave.config[:s3][:access]
|
37
|
+
end
|
38
|
+
|
39
|
+
##
|
40
|
+
# Store the file on S3
|
41
|
+
#
|
42
|
+
# @param [CarrierWave::Uploader] uploader an uploader object
|
43
|
+
# @param [CarrierWave::SanitizedFile] file the file to store
|
44
|
+
#
|
45
|
+
# @return [#identifier] an object
|
46
|
+
#
|
47
|
+
def self.store!(uploader, file)
|
48
|
+
AWS::S3::S3Object.store(::File.join(uploader.store_dir, uploader.filename), file.read, bucket, :access => access)
|
49
|
+
self.new(bucket, uploader.store_dir, uploader.filename)
|
50
|
+
end
|
51
|
+
|
52
|
+
# Do something to retrieve the file
|
53
|
+
#
|
54
|
+
# @param [CarrierWave::Uploader] uploader an uploader object
|
55
|
+
# @param [String] identifier uniquely identifies the file
|
56
|
+
#
|
57
|
+
# @return [#identifier] an object
|
58
|
+
#
|
59
|
+
def self.retrieve!(uploader, identifier)
|
60
|
+
self.new(bucket, uploader.store_dir, identifier)
|
61
|
+
end
|
62
|
+
|
63
|
+
##
|
64
|
+
# Returns the filename on S3
|
65
|
+
#
|
66
|
+
# @return [String] path to the file
|
67
|
+
#
|
68
|
+
def identifier
|
69
|
+
@identifier
|
70
|
+
end
|
71
|
+
|
72
|
+
##
|
73
|
+
# Returns the url on Amazon's S3 service
|
74
|
+
#
|
75
|
+
# @return [String] file's url
|
76
|
+
#
|
77
|
+
def url
|
78
|
+
"http://s3.amazonaws.com/#{self.class.bucket}/#{@store_dir}/#{@identifier}"
|
79
|
+
end
|
80
|
+
|
81
|
+
end # S3
|
82
|
+
end # Storage
|
83
|
+
end # CarrierWave
|
@@ -0,0 +1,427 @@
|
|
1
|
+
module CarrierWave
|
2
|
+
class Uploader
|
3
|
+
|
4
|
+
class << self
|
5
|
+
|
6
|
+
##
|
7
|
+
# Returns a list of processor callbacks which have been declared for this uploader
|
8
|
+
#
|
9
|
+
# @return [String]
|
10
|
+
#
|
11
|
+
def processors
|
12
|
+
@processors ||= []
|
13
|
+
end
|
14
|
+
|
15
|
+
##
|
16
|
+
# Adds a processor callback which applies operations as a file is uploaded.
|
17
|
+
# The argument may be the name of any method of the uploader, expressed as a symbol,
|
18
|
+
# or a list of such methods, or a hash where the key is a method and the value is
|
19
|
+
# an array of arguments to call the method with
|
20
|
+
#
|
21
|
+
# @param [*Symbol, Hash{Symbol => Array[]}] args
|
22
|
+
# @example
|
23
|
+
# class MyUploader < CarrierWave::Uploader
|
24
|
+
# process :sepiatone, :vignette
|
25
|
+
# process :scale => [200, 200]
|
26
|
+
#
|
27
|
+
# def sepiatone
|
28
|
+
# ...
|
29
|
+
# end
|
30
|
+
#
|
31
|
+
# def vignette
|
32
|
+
# ...
|
33
|
+
# end
|
34
|
+
#
|
35
|
+
# def scale(height, width)
|
36
|
+
# ...
|
37
|
+
# end
|
38
|
+
# end
|
39
|
+
#
|
40
|
+
def process(*args)
|
41
|
+
args.each do |arg|
|
42
|
+
if arg.is_a?(Hash)
|
43
|
+
arg.each do |method, args|
|
44
|
+
processors.push([method, args])
|
45
|
+
end
|
46
|
+
else
|
47
|
+
processors.push([arg, []])
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
##
|
53
|
+
# Sets the storage engine to be used when storing files with this uploader.
|
54
|
+
# Can be any class that implements a #store!(CarrierWave::SanitizedFile) and a #retrieve!
|
55
|
+
# method. See lib/carrierwave/storage/file.rb for an example. Storage engines should
|
56
|
+
# be added to CarrierWave.config[:storage_engines] so they can be referred
|
57
|
+
# to by a symbol, which should be more convenient
|
58
|
+
#
|
59
|
+
# If no argument is given, it will simply return the currently used storage engine.
|
60
|
+
#
|
61
|
+
# @param [Symbol, Class] storage The storage engine to use for this uploader
|
62
|
+
# @return [Class] the storage engine to be used with this uploader
|
63
|
+
# @example
|
64
|
+
# storage :file
|
65
|
+
# storage CarrierWave::Storage::File
|
66
|
+
# storage MyCustomStorageEngine
|
67
|
+
#
|
68
|
+
def storage(storage = nil)
|
69
|
+
if storage.is_a?(Symbol)
|
70
|
+
@storage = get_storage_by_symbol(storage)
|
71
|
+
@storage.setup!
|
72
|
+
elsif storage
|
73
|
+
@storage = storage
|
74
|
+
@storage.setup!
|
75
|
+
elsif @storage.nil?
|
76
|
+
# Get the storage from the superclass if there is one
|
77
|
+
@storage = superclass.storage rescue nil
|
78
|
+
end
|
79
|
+
if @storage.nil?
|
80
|
+
# If we were not able to find a store any other way, setup the default store
|
81
|
+
@storage ||= get_storage_by_symbol(CarrierWave.config[:storage])
|
82
|
+
@storage.setup!
|
83
|
+
end
|
84
|
+
return @storage
|
85
|
+
end
|
86
|
+
|
87
|
+
alias_method :storage=, :storage
|
88
|
+
|
89
|
+
attr_accessor :version_name
|
90
|
+
|
91
|
+
##
|
92
|
+
# Adds a new version to this uploader
|
93
|
+
#
|
94
|
+
# @param [#to_sym] name name of the version
|
95
|
+
# @param [Proc] &block a block to eval on this version of the uploader
|
96
|
+
#
|
97
|
+
def version(name, &block)
|
98
|
+
name = name.to_sym
|
99
|
+
klass = Class.new(self)
|
100
|
+
klass.version_name = name
|
101
|
+
klass.class_eval(&block) if block
|
102
|
+
versions[name] = klass
|
103
|
+
class_eval <<-RUBY
|
104
|
+
def #{name}
|
105
|
+
versions[:#{name}]
|
106
|
+
end
|
107
|
+
RUBY
|
108
|
+
end
|
109
|
+
|
110
|
+
##
|
111
|
+
# @return [Hash{Symbol => Class}] a list of versions available for this uploader
|
112
|
+
#
|
113
|
+
def versions
|
114
|
+
@versions ||= {}
|
115
|
+
end
|
116
|
+
|
117
|
+
##
|
118
|
+
# Generates a unique cache id for use in the caching system
|
119
|
+
#
|
120
|
+
# @return [String] a cache if in the format YYYYMMDD-HHMM-PID-RND
|
121
|
+
#
|
122
|
+
def generate_cache_id
|
123
|
+
Time.now.strftime('%Y%m%d-%H%M') + '-' + Process.pid.to_s + '-' + ("%04d" % rand(9999))
|
124
|
+
end
|
125
|
+
|
126
|
+
private
|
127
|
+
|
128
|
+
def get_storage_by_symbol(symbol)
|
129
|
+
CarrierWave.config[:storage_engines][symbol]
|
130
|
+
end
|
131
|
+
|
132
|
+
end # class << self
|
133
|
+
|
134
|
+
attr_reader :file, :model, :mounted_as
|
135
|
+
|
136
|
+
##
|
137
|
+
# If a model is given as the first parameter, it will stored in the uploader, and
|
138
|
+
# available throught +#model+. Likewise, mounted_as stores the name of the column
|
139
|
+
# where this instance of the uploader is mounted. These values can then be used inside
|
140
|
+
# your uploader.
|
141
|
+
#
|
142
|
+
# If you do not wish to mount your uploaders with the ORM extensions in -more then you
|
143
|
+
# can override this method inside your uploader.
|
144
|
+
#
|
145
|
+
# @param [Object] model Any kind of model object
|
146
|
+
# @param [Symbol] mounted_as The name of the column where this uploader is mounted
|
147
|
+
# @example
|
148
|
+
# class MyUploader < CarrierWave::Uploader
|
149
|
+
# def store_dir
|
150
|
+
# File.join('public', 'files', mounted_as, model.permalink)
|
151
|
+
# end
|
152
|
+
# end
|
153
|
+
#
|
154
|
+
def initialize(model=nil, mounted_as=nil)
|
155
|
+
@model = model
|
156
|
+
@mounted_as = mounted_as
|
157
|
+
end
|
158
|
+
|
159
|
+
##
|
160
|
+
# @return [Boolean] Whether the uploaded file is blank
|
161
|
+
#
|
162
|
+
def blank?
|
163
|
+
!file or file.empty?
|
164
|
+
end
|
165
|
+
|
166
|
+
##
|
167
|
+
# Apply all process callbacks added through CarrierWave.process
|
168
|
+
#
|
169
|
+
def process!
|
170
|
+
self.class.processors.each do |method, args|
|
171
|
+
self.send(method, *args)
|
172
|
+
end
|
173
|
+
end
|
174
|
+
|
175
|
+
##
|
176
|
+
# @return [String] the path where the file is currently located.
|
177
|
+
#
|
178
|
+
def current_path
|
179
|
+
file.path if file.respond_to?(:path)
|
180
|
+
end
|
181
|
+
|
182
|
+
##
|
183
|
+
# Returns a hash mapping the name of each version of the uploader to an instance of it
|
184
|
+
#
|
185
|
+
# @return [Hash{Symbol => CarrierWave::Uploader}] a list of uploader instances
|
186
|
+
#
|
187
|
+
def versions
|
188
|
+
return @versions if @versions
|
189
|
+
@versions = {}
|
190
|
+
self.class.versions.each do |name, klass|
|
191
|
+
@versions[name] = klass.new(model, mounted_as)
|
192
|
+
end
|
193
|
+
@versions
|
194
|
+
end
|
195
|
+
|
196
|
+
##
|
197
|
+
# @return [String] the location where this file is accessible via a url
|
198
|
+
#
|
199
|
+
def url
|
200
|
+
if file.respond_to?(:url) and not file.url.blank?
|
201
|
+
file.url
|
202
|
+
elsif current_path
|
203
|
+
File.expand_path(current_path).gsub(File.expand_path(public), '')
|
204
|
+
end
|
205
|
+
end
|
206
|
+
|
207
|
+
alias_method :to_s, :url
|
208
|
+
|
209
|
+
##
|
210
|
+
# Returns a string that uniquely identifies the last stored file
|
211
|
+
#
|
212
|
+
# @return [String] uniquely identifies a file
|
213
|
+
#
|
214
|
+
def identifier
|
215
|
+
file.identifier if file.respond_to?(:identifier)
|
216
|
+
end
|
217
|
+
|
218
|
+
##
|
219
|
+
# Override this in your Uploader to change the filename.
|
220
|
+
#
|
221
|
+
# Be careful using record ids as filenames. If the filename is stored in the database
|
222
|
+
# the record id will be nil when the filename is set. Don't use record ids unless you
|
223
|
+
# understand this limitation.
|
224
|
+
#
|
225
|
+
# Do not use the version_name in the filename, as it will prevent versions from being
|
226
|
+
# loaded correctly.
|
227
|
+
#
|
228
|
+
# @return [String] a filename
|
229
|
+
#
|
230
|
+
def filename
|
231
|
+
@filename
|
232
|
+
end
|
233
|
+
|
234
|
+
##
|
235
|
+
# @return [String] the name of this version of the uploader
|
236
|
+
#
|
237
|
+
def version_name
|
238
|
+
self.class.version_name
|
239
|
+
end
|
240
|
+
|
241
|
+
##
|
242
|
+
# @return [String] the directory that is the root of the application
|
243
|
+
#
|
244
|
+
def root
|
245
|
+
CarrierWave.config[:root]
|
246
|
+
end
|
247
|
+
|
248
|
+
##
|
249
|
+
# @return [String] the directory where files will be publically accessible
|
250
|
+
#
|
251
|
+
def public
|
252
|
+
CarrierWave.config[:public]
|
253
|
+
end
|
254
|
+
|
255
|
+
####################
|
256
|
+
## Cache
|
257
|
+
####################
|
258
|
+
|
259
|
+
##
|
260
|
+
# Override this in your Uploader to change the directory where files are cached.
|
261
|
+
#
|
262
|
+
# @return [String] a directory
|
263
|
+
#
|
264
|
+
def cache_dir
|
265
|
+
CarrierWave.config[:cache_dir]
|
266
|
+
end
|
267
|
+
|
268
|
+
##
|
269
|
+
# Returns a String which uniquely identifies the currently cached file for later retrieval
|
270
|
+
#
|
271
|
+
# @return [String] a cache name, in the format YYYYMMDD-HHMM-PID-RND/filename.txt
|
272
|
+
#
|
273
|
+
def cache_name
|
274
|
+
File.join(cache_id, [version_name, original_filename].compact.join('_')) if cache_id and original_filename
|
275
|
+
end
|
276
|
+
|
277
|
+
##
|
278
|
+
# Caches the given file unless a file has already been cached, stored or retrieved.
|
279
|
+
#
|
280
|
+
# @param [File, IOString, Tempfile] new_file any kind of file object
|
281
|
+
# @raise [CarrierWave::FormNotMultipart] if the assigned parameter is a string
|
282
|
+
#
|
283
|
+
def cache(new_file)
|
284
|
+
cache!(new_file) unless file
|
285
|
+
end
|
286
|
+
|
287
|
+
##
|
288
|
+
# Caches the given file. Calls process! to trigger any process callbacks.
|
289
|
+
#
|
290
|
+
# @param [File, IOString, Tempfile] new_file any kind of file object
|
291
|
+
# @raise [CarrierWave::FormNotMultipart] if the assigned parameter is a string
|
292
|
+
#
|
293
|
+
def cache!(new_file)
|
294
|
+
new_file = CarrierWave::SanitizedFile.new(new_file)
|
295
|
+
raise CarrierWave::FormNotMultipart if new_file.string?
|
296
|
+
|
297
|
+
unless new_file.empty?
|
298
|
+
self.cache_id = CarrierWave::Uploader.generate_cache_id unless cache_id
|
299
|
+
|
300
|
+
@file = new_file
|
301
|
+
|
302
|
+
@filename = new_file.filename
|
303
|
+
self.original_filename = new_file.filename
|
304
|
+
|
305
|
+
@file = @file.copy_to(cache_path)
|
306
|
+
process!
|
307
|
+
|
308
|
+
versions.each do |name, v|
|
309
|
+
v.send(:cache_id=, cache_id)
|
310
|
+
v.cache!(new_file)
|
311
|
+
end
|
312
|
+
end
|
313
|
+
end
|
314
|
+
|
315
|
+
##
|
316
|
+
# Retrieves the file with the given cache_name from the cache, unless a file has
|
317
|
+
# already been cached, stored or retrieved.
|
318
|
+
#
|
319
|
+
# @param [String] cache_name uniquely identifies a cache file
|
320
|
+
#
|
321
|
+
def retrieve_from_cache(cache_name)
|
322
|
+
retrieve_from_cache!(cache_name) unless file
|
323
|
+
rescue CarrierWave::InvalidParameter
|
324
|
+
end
|
325
|
+
|
326
|
+
##
|
327
|
+
# Retrieves the file with the given cache_name from the cache.
|
328
|
+
#
|
329
|
+
# @param [String] cache_name uniquely identifies a cache file
|
330
|
+
# @raise [CarrierWave::InvalidParameter] if the cache_name is incorrectly formatted.
|
331
|
+
#
|
332
|
+
def retrieve_from_cache!(cache_name)
|
333
|
+
self.cache_id, self.original_filename = cache_name.split('/', 2)
|
334
|
+
@filename = original_filename
|
335
|
+
@file = CarrierWave::SanitizedFile.new(cache_path)
|
336
|
+
versions.each { |name, v| v.retrieve_from_cache!(cache_name) }
|
337
|
+
end
|
338
|
+
|
339
|
+
####################
|
340
|
+
## STORE
|
341
|
+
####################
|
342
|
+
|
343
|
+
##
|
344
|
+
# Override this in your Uploader to change the directory where the file backend stores files.
|
345
|
+
#
|
346
|
+
# Other backends may or may not use this method, depending on their specific needs.
|
347
|
+
#
|
348
|
+
# @return [String] a directory
|
349
|
+
#
|
350
|
+
def store_dir
|
351
|
+
[CarrierWave.config[:store_dir], version_name].compact.join(File::Separator)
|
352
|
+
end
|
353
|
+
|
354
|
+
##
|
355
|
+
# Stores the file by passing it to this Uploader's storage engine, unless a file has
|
356
|
+
# already been cached, stored or retrieved.
|
357
|
+
#
|
358
|
+
# If CarrierWave.config[:use_cache] is true, it will first cache the file
|
359
|
+
# and apply any process callbacks before uploading it.
|
360
|
+
#
|
361
|
+
# @param [File, IOString, Tempfile] new_file any kind of file object
|
362
|
+
#
|
363
|
+
def store(new_file)
|
364
|
+
store!(new_file) unless file
|
365
|
+
end
|
366
|
+
|
367
|
+
##
|
368
|
+
# Stores the file by passing it to this Uploader's storage engine.
|
369
|
+
#
|
370
|
+
# If new_file is omitted, a previously cached file will be stored.
|
371
|
+
#
|
372
|
+
# @param [File, IOString, Tempfile] new_file any kind of file object
|
373
|
+
#
|
374
|
+
def store!(new_file=nil)
|
375
|
+
cache!(new_file) if new_file
|
376
|
+
if @file
|
377
|
+
@file = storage.store!(self, @file)
|
378
|
+
@cache_id = nil
|
379
|
+
versions.each { |name, v| v.store!(new_file) }
|
380
|
+
end
|
381
|
+
end
|
382
|
+
|
383
|
+
##
|
384
|
+
# Retrieves the file from the storage, unless a file has
|
385
|
+
# already been cached, stored or retrieved.
|
386
|
+
#
|
387
|
+
# @param [String] identifier uniquely identifies the file to retrieve
|
388
|
+
#
|
389
|
+
def retrieve_from_store(identifier)
|
390
|
+
retrieve_from_store!(identifier) unless file
|
391
|
+
rescue CarrierWave::InvalidParameter
|
392
|
+
end
|
393
|
+
|
394
|
+
##
|
395
|
+
# Retrieves the file from the storage.
|
396
|
+
#
|
397
|
+
# @param [String] identifier uniquely identifies the file to retrieve
|
398
|
+
#
|
399
|
+
def retrieve_from_store!(identifier)
|
400
|
+
@file = storage.retrieve!(self, identifier)
|
401
|
+
versions.each { |name, v| v.retrieve_from_store!(identifier) }
|
402
|
+
end
|
403
|
+
|
404
|
+
private
|
405
|
+
|
406
|
+
def cache_path
|
407
|
+
File.expand_path(File.join(cache_dir, cache_name), public)
|
408
|
+
end
|
409
|
+
|
410
|
+
def storage
|
411
|
+
self.class.storage
|
412
|
+
end
|
413
|
+
|
414
|
+
attr_reader :cache_id, :original_filename
|
415
|
+
|
416
|
+
def cache_id=(cache_id)
|
417
|
+
raise CarrierWave::InvalidParameter, "invalid cache id" unless cache_id =~ /^[\d]{8}\-[\d]{4}\-[\d]+\-[\d]{4}$/
|
418
|
+
@cache_id = cache_id
|
419
|
+
end
|
420
|
+
|
421
|
+
def original_filename=(filename)
|
422
|
+
raise CarrierWave::InvalidParameter, "invalid filename" unless filename =~ /^[a-z0-9\.\-\+_]+$/i
|
423
|
+
@original_filename = filename
|
424
|
+
end
|
425
|
+
|
426
|
+
end # Uploader
|
427
|
+
end # CarrierWave
|