carrierwave 0.5.4 → 0.5.5
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/README.md +716 -0
- data/lib/carrierwave.rb +7 -0
- data/lib/carrierwave/mount.rb +38 -11
- data/lib/carrierwave/orm/activerecord.rb +5 -2
- data/lib/carrierwave/orm/mongoid.rb +40 -5
- data/lib/carrierwave/processing/image_science.rb +0 -4
- data/lib/carrierwave/processing/mime_types.rb +58 -0
- data/lib/carrierwave/processing/mini_magick.rb +7 -16
- data/lib/carrierwave/sanitized_file.rb +21 -4
- data/lib/carrierwave/uploader/cache.rb +13 -4
- data/lib/carrierwave/uploader/configuration.rb +9 -9
- data/lib/carrierwave/uploader/download.rb +1 -1
- data/lib/carrierwave/uploader/processing.rb +20 -14
- data/lib/carrierwave/uploader/proxy.rb +16 -1
- data/lib/carrierwave/uploader/store.rb +11 -0
- data/lib/carrierwave/uploader/versions.rb +79 -21
- data/lib/carrierwave/version.rb +1 -1
- metadata +55 -136
- data/README.rdoc +0 -647
- data/lib/carrierwave/orm/datamapper.rb +0 -37
- data/lib/carrierwave/orm/sequel.rb +0 -45
data/lib/carrierwave.rb
CHANGED
@@ -3,6 +3,12 @@
|
|
3
3
|
require 'fileutils'
|
4
4
|
require 'active_support/core_ext/object/blank'
|
5
5
|
require 'active_support/core_ext/class/attribute'
|
6
|
+
|
7
|
+
begin
|
8
|
+
require 'active_support/core_ext/class/inheritable_attributes'
|
9
|
+
rescue LoadError
|
10
|
+
end
|
11
|
+
|
6
12
|
require 'active_support/concern'
|
7
13
|
require 'active_support/memoizable'
|
8
14
|
|
@@ -31,6 +37,7 @@ module CarrierWave
|
|
31
37
|
autoload :RMagick, 'carrierwave/processing/rmagick'
|
32
38
|
autoload :ImageScience, 'carrierwave/processing/image_science'
|
33
39
|
autoload :MiniMagick, 'carrierwave/processing/mini_magick'
|
40
|
+
autoload :MimeTypes, 'carrierwave/processing/mime_types'
|
34
41
|
autoload :VERSION, 'carrierwave/version'
|
35
42
|
|
36
43
|
module Storage
|
data/lib/carrierwave/mount.rb
CHANGED
@@ -65,10 +65,11 @@ module CarrierWave
|
|
65
65
|
# @user.image.url # => '/some_url.png'
|
66
66
|
#
|
67
67
|
# It is also possible (but not recommended) to ommit the uploader, which
|
68
|
-
# will create an anonymous uploader class.
|
69
|
-
#
|
70
|
-
#
|
71
|
-
#
|
68
|
+
# will create an anonymous uploader class.
|
69
|
+
#
|
70
|
+
# Passing a block makes it possible to customize the uploader. This can be
|
71
|
+
# convenient for brevity, but if there is any significatnt logic in the
|
72
|
+
# uploader, you should do the right thing and have it in its own file.
|
72
73
|
#
|
73
74
|
# === Added instance methods
|
74
75
|
#
|
@@ -97,6 +98,7 @@ module CarrierWave
|
|
97
98
|
# [image_processing_error] Returns an error object if the last file to be assigned caused a processing error
|
98
99
|
#
|
99
100
|
# [write_image_identifier] Uses the write_uploader method to set the identifier.
|
101
|
+
# [image_identifier] Reads out the identifier of the file
|
100
102
|
#
|
101
103
|
# === Parameters
|
102
104
|
#
|
@@ -138,9 +140,12 @@ module CarrierWave
|
|
138
140
|
# end
|
139
141
|
#
|
140
142
|
def mount_uploader(column, uploader=nil, options={}, &block)
|
141
|
-
|
142
|
-
uploader = Class.new(CarrierWave::Uploader::Base)
|
143
|
+
if block_given?
|
144
|
+
uploader = Class.new(uploader || CarrierWave::Uploader::Base)
|
143
145
|
uploader.class_eval(&block)
|
146
|
+
uploader.recursively_apply_block_to_versions(&block)
|
147
|
+
else
|
148
|
+
uploader ||= Class.new(CarrierWave::Uploader::Base)
|
144
149
|
end
|
145
150
|
|
146
151
|
uploaders[column.to_sym] = uploader
|
@@ -226,8 +231,30 @@ module CarrierWave
|
|
226
231
|
_mounter(:#{column}).write_identifier
|
227
232
|
end
|
228
233
|
|
229
|
-
|
234
|
+
def #{column}_identifier
|
235
|
+
_mounter(:#{column}).identifier
|
236
|
+
end
|
237
|
+
|
238
|
+
def store_previous_model_for_#{column}
|
239
|
+
serialization_column = _mounter(:#{column}).serialization_column
|
240
|
+
|
241
|
+
if #{column}.remove_previously_stored_files_after_update && send(:"\#{serialization_column}_changed?")
|
242
|
+
@previous_model_for_#{column} ||= self.find_previous_model_for_#{column}
|
243
|
+
end
|
244
|
+
end
|
245
|
+
|
246
|
+
def find_previous_model_for_#{column}
|
247
|
+
self.class.find(to_key.first)
|
248
|
+
end
|
249
|
+
|
250
|
+
def remove_previously_stored_#{column}
|
251
|
+
if @previous_model_for_#{column} && @previous_model_for_#{column}.#{column}.path != #{column}.path
|
252
|
+
@previous_model_for_#{column}.#{column}.remove!
|
253
|
+
@previous_model_for_#{column} = nil
|
254
|
+
end
|
255
|
+
end
|
230
256
|
|
257
|
+
RUBY
|
231
258
|
end
|
232
259
|
|
233
260
|
module Extension
|
@@ -342,6 +369,10 @@ module CarrierWave
|
|
342
369
|
uploader.remove!
|
343
370
|
end
|
344
371
|
|
372
|
+
def serialization_column
|
373
|
+
option(:mount_on) || column
|
374
|
+
end
|
375
|
+
|
345
376
|
private
|
346
377
|
|
347
378
|
def option(name)
|
@@ -349,10 +380,6 @@ module CarrierWave
|
|
349
380
|
end
|
350
381
|
memoize :option
|
351
382
|
|
352
|
-
def serialization_column
|
353
|
-
option(:mount_on) || column
|
354
|
-
end
|
355
|
-
|
356
383
|
end # Mounter
|
357
384
|
|
358
385
|
end # Mount
|
@@ -11,7 +11,7 @@ module CarrierWave
|
|
11
11
|
##
|
12
12
|
# See +CarrierWave::Mount#mount_uploader+ for documentation
|
13
13
|
#
|
14
|
-
def mount_uploader(column, uploader, options={}, &block)
|
14
|
+
def mount_uploader(column, uploader=nil, options={}, &block)
|
15
15
|
super
|
16
16
|
|
17
17
|
alias_method :read_uploader, :read_attribute
|
@@ -27,10 +27,13 @@ module CarrierWave
|
|
27
27
|
after_save :"store_#{column}!"
|
28
28
|
before_save :"write_#{column}_identifier"
|
29
29
|
after_destroy :"remove_#{column}!"
|
30
|
+
before_update :"store_previous_model_for_#{column}"
|
31
|
+
after_save :"remove_previously_stored_#{column}"
|
30
32
|
|
31
33
|
class_eval <<-RUBY, __FILE__, __LINE__+1
|
32
34
|
def #{column}=(new_file)
|
33
|
-
|
35
|
+
column = _mounter(:#{column}).serialization_column
|
36
|
+
send(:"\#{column}_will_change!")
|
34
37
|
super
|
35
38
|
end
|
36
39
|
RUBY
|
@@ -9,7 +9,7 @@ module CarrierWave
|
|
9
9
|
##
|
10
10
|
# See +CarrierWave::Mount#mount_uploader+ for documentation
|
11
11
|
#
|
12
|
-
def mount_uploader(column, uploader, options={}, &block)
|
12
|
+
def mount_uploader(column, uploader=nil, options={}, &block)
|
13
13
|
options[:mount_on] ||= "#{column}_filename"
|
14
14
|
field options[:mount_on]
|
15
15
|
|
@@ -23,11 +23,46 @@ module CarrierWave
|
|
23
23
|
validates_integrity_of column if uploader_option(column.to_sym, :validate_integrity)
|
24
24
|
validates_processing_of column if uploader_option(column.to_sym, :validate_processing)
|
25
25
|
|
26
|
-
after_save
|
27
|
-
before_save
|
28
|
-
after_destroy
|
26
|
+
after_save :"store_#{column}!"
|
27
|
+
before_save :"write_#{column}_identifier"
|
28
|
+
after_destroy :"remove_#{column}!"
|
29
|
+
before_update :"store_previous_model_for_#{column}"
|
30
|
+
after_save :"remove_previously_stored_#{column}"
|
31
|
+
|
32
|
+
class_eval <<-RUBY, __FILE__, __LINE__+1
|
33
|
+
def #{column}=(new_file)
|
34
|
+
column = _mounter(:#{column}).serialization_column
|
35
|
+
|
36
|
+
# Note (Didier L.): equivalent of the <column>_will_change! ActiveModel method
|
37
|
+
begin
|
38
|
+
value = __send__(column)
|
39
|
+
value = value.duplicable? ? value.clone : value
|
40
|
+
rescue TypeError, NoMethodError
|
41
|
+
end
|
42
|
+
setup_modifications
|
43
|
+
|
44
|
+
super.tap do
|
45
|
+
@modifications[column] = [value, __send__(column)]
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def #{column}_changed?
|
50
|
+
column = _mounter(:#{column}).serialization_column
|
51
|
+
send(:"\#{column}_changed?")
|
52
|
+
end
|
53
|
+
|
54
|
+
def find_previous_model_for_#{column}
|
55
|
+
if self.embedded?
|
56
|
+
self._parent.reload.send(self.metadata.key).find(to_key.first)
|
57
|
+
else
|
58
|
+
self.class.find(to_key.first)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
RUBY
|
63
|
+
|
29
64
|
end
|
30
65
|
end # Mongoid
|
31
66
|
end # CarrierWave
|
32
67
|
|
33
|
-
Mongoid::Document::ClassMethods.send(:include, CarrierWave::Mongoid)
|
68
|
+
Mongoid::Document::ClassMethods.send(:include, CarrierWave::Mongoid)
|
@@ -26,8 +26,6 @@ module CarrierWave
|
|
26
26
|
# specified in the smaller dimension but will not be larger than the
|
27
27
|
# specified values.
|
28
28
|
#
|
29
|
-
# See even http://www.imagemagick.org/RMagick/doc/image3.html#resize_to_fit
|
30
|
-
#
|
31
29
|
# === Parameters
|
32
30
|
#
|
33
31
|
# [width (Integer)] the width to scale the image to
|
@@ -49,8 +47,6 @@ module CarrierWave
|
|
49
47
|
# the aspect ratio of the original image. If necessary, crop the image in
|
50
48
|
# the larger dimension.
|
51
49
|
#
|
52
|
-
# See even http://www.imagemagick.org/RMagick/doc/image3.html#resize_to_fill
|
53
|
-
#
|
54
50
|
# === Parameters
|
55
51
|
#
|
56
52
|
# [width (Integer)] the width to scale the image to
|
@@ -0,0 +1,58 @@
|
|
1
|
+
require 'mime/types'
|
2
|
+
|
3
|
+
module CarrierWave
|
4
|
+
|
5
|
+
##
|
6
|
+
# This module simplifies the use of the mime-types gem to intelligently
|
7
|
+
# guess and set the content-type of a file. If you want to use this, you'll
|
8
|
+
# need to require this file:
|
9
|
+
#
|
10
|
+
# require 'carrierwave/processing/mime_types'
|
11
|
+
#
|
12
|
+
# And then include it in your uploader:
|
13
|
+
#
|
14
|
+
# class MyUploader < CarrierWave::Uploader::Base
|
15
|
+
# include CarrierWave::MimeTypes
|
16
|
+
# end
|
17
|
+
#
|
18
|
+
# You can now use the provided helper:
|
19
|
+
#
|
20
|
+
# class MyUploader < CarrierWave::Uploader::Base
|
21
|
+
# include CarrierWave::MimeTypes
|
22
|
+
#
|
23
|
+
# process :set_content_type
|
24
|
+
# end
|
25
|
+
#
|
26
|
+
module MimeTypes
|
27
|
+
extend ActiveSupport::Concern
|
28
|
+
|
29
|
+
module ClassMethods
|
30
|
+
def set_content_type(override=false)
|
31
|
+
process :set_content_type => override
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
##
|
36
|
+
# Changes the file content_type using the mime-types gem
|
37
|
+
#
|
38
|
+
# === Parameters
|
39
|
+
#
|
40
|
+
# [override (Boolean)] whether or not to override the file's content_type
|
41
|
+
# if it is already set and not a generic content-type,
|
42
|
+
# false by default
|
43
|
+
#
|
44
|
+
def set_content_type(override=false)
|
45
|
+
if override || file.content_type.blank? || file.content_type == 'application/octet-stream'
|
46
|
+
new_content_type = ::MIME::Types.type_for(file.original_filename).first.to_s
|
47
|
+
if file.respond_to?(:content_type=)
|
48
|
+
file.content_type = new_content_type
|
49
|
+
else
|
50
|
+
file.set_instance_variable(:@content_type, new_content_type)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
rescue ::MIME::InvalidContentType => e
|
54
|
+
raise CarrierWave::ProcessingError.new("Failed to process file with MIME::Types, maybe not valid content-type? Original Error: #{e}")
|
55
|
+
end
|
56
|
+
|
57
|
+
end # MimeTypes
|
58
|
+
end # CarrierWave
|
@@ -129,12 +129,9 @@ module CarrierWave
|
|
129
129
|
end
|
130
130
|
|
131
131
|
##
|
132
|
-
#
|
133
|
-
#
|
134
|
-
#
|
135
|
-
# but will not be larger than the specified values."
|
136
|
-
#
|
137
|
-
# See even http://www.imagemagick.org/RMagick/doc/image3.html#resize_to_fit
|
132
|
+
# Resize the image to fit within the specified dimensions while retaining
|
133
|
+
# the original aspect ratio. The image may be shorter or narrower than
|
134
|
+
# specified in the smaller dimension but will not be larger than the specified values.
|
138
135
|
#
|
139
136
|
# === Parameters
|
140
137
|
#
|
@@ -154,15 +151,9 @@ module CarrierWave
|
|
154
151
|
end
|
155
152
|
|
156
153
|
##
|
157
|
-
#
|
158
|
-
#
|
159
|
-
#
|
160
|
-
#
|
161
|
-
# See even http://www.imagemagick.org/RMagick/doc/image3.html#resize_to_fill
|
162
|
-
#
|
163
|
-
# and
|
164
|
-
#
|
165
|
-
# http://www.clipclip.org/clips/detail/4365/jerrett-net-»-crop_resized-in-rmagick
|
154
|
+
# Resize the image to fit within the specified dimensions while retaining
|
155
|
+
# the aspect ratio of the original image. If necessary, crop the image in the
|
156
|
+
# larger dimension.
|
166
157
|
#
|
167
158
|
# === Parameters
|
168
159
|
#
|
@@ -229,7 +220,7 @@ module CarrierWave
|
|
229
220
|
end
|
230
221
|
|
231
222
|
##
|
232
|
-
# Manipulate the image with
|
223
|
+
# Manipulate the image with MiniMagick. This method will load up an image
|
233
224
|
# and then pass each of its frames to the supplied block. It will then
|
234
225
|
# save the image to disk.
|
235
226
|
#
|
@@ -17,6 +17,14 @@ module CarrierWave
|
|
17
17
|
|
18
18
|
attr_accessor :file
|
19
19
|
|
20
|
+
class << self
|
21
|
+
attr_writer :sanitize_regexp
|
22
|
+
|
23
|
+
def sanitize_regexp
|
24
|
+
@sanitize_regexp ||= /[^a-zA-Z0-9\.\-\+_]/
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
20
28
|
def initialize(file)
|
21
29
|
self.file = file
|
22
30
|
end
|
@@ -127,8 +135,6 @@ module CarrierWave
|
|
127
135
|
@file.nil? || self.size.nil? || self.size.zero?
|
128
136
|
end
|
129
137
|
|
130
|
-
alias_method :blank?, :empty?
|
131
|
-
|
132
138
|
##
|
133
139
|
# === Returns
|
134
140
|
#
|
@@ -222,6 +228,17 @@ module CarrierWave
|
|
222
228
|
@file.content_type.chomp if @file.respond_to?(:content_type) and @file.content_type
|
223
229
|
end
|
224
230
|
|
231
|
+
##
|
232
|
+
# Sets the content type of the file.
|
233
|
+
#
|
234
|
+
# === Returns
|
235
|
+
#
|
236
|
+
# [String] the content type of the file
|
237
|
+
#
|
238
|
+
def content_type=(type)
|
239
|
+
@content_type = type
|
240
|
+
end
|
241
|
+
|
225
242
|
##
|
226
243
|
# Used to sanitize the file name. Public to allow overriding for non-latin characters.
|
227
244
|
#
|
@@ -230,7 +247,7 @@ module CarrierWave
|
|
230
247
|
# [Regexp] the regexp for sanitizing the file name
|
231
248
|
#
|
232
249
|
def sanitize_regexp
|
233
|
-
|
250
|
+
CarrierWave::SanitizedFile.sanitize_regexp
|
234
251
|
end
|
235
252
|
|
236
253
|
private
|
@@ -263,7 +280,7 @@ module CarrierWave
|
|
263
280
|
name = name.gsub(sanitize_regexp,"_")
|
264
281
|
name = "_#{name}" if name =~ /\A\.+\z/
|
265
282
|
name = "unnamed" if name.size == 0
|
266
|
-
return name.mb_chars.
|
283
|
+
return name.mb_chars.to_s
|
267
284
|
end
|
268
285
|
|
269
286
|
def split_extension(filename)
|
@@ -41,11 +41,11 @@ module CarrierWave
|
|
41
41
|
# This only works as long as you haven't done anything funky with your cache_dir.
|
42
42
|
# It's recommended that you keep cache files in one place only.
|
43
43
|
#
|
44
|
-
def clean_cached_files!
|
44
|
+
def clean_cached_files!(seconds=60*60*24)
|
45
45
|
Dir.glob(File.expand_path(File.join(cache_dir, '*'), CarrierWave.root)).each do |dir|
|
46
46
|
time = dir.scan(/(\d{4})(\d{2})(\d{2})-(\d{2})(\d{2})/).first.map { |t| t.to_i }
|
47
47
|
time = Time.utc(*time)
|
48
|
-
if time < (Time.now.utc -
|
48
|
+
if time < (Time.now.utc - seconds)
|
49
49
|
FileUtils.rm_rf(dir)
|
50
50
|
end
|
51
51
|
end
|
@@ -130,7 +130,16 @@ module CarrierWave
|
|
130
130
|
with_callbacks(:retrieve_from_cache, cache_name) do
|
131
131
|
self.cache_id, self.original_filename = cache_name.to_s.split('/', 2)
|
132
132
|
@filename = original_filename
|
133
|
-
|
133
|
+
|
134
|
+
if File.exist?(cache_path) && defined?(MIME::Types)
|
135
|
+
@file = SanitizedFile.new(
|
136
|
+
:tempfile => cache_path,
|
137
|
+
:filename => @filename,
|
138
|
+
:content_type => MIME::Types.of(File.basename(cache_path))[0].content_type
|
139
|
+
)
|
140
|
+
else
|
141
|
+
@file = CarrierWave::SanitizedFile.new(cache_path)
|
142
|
+
end
|
134
143
|
end
|
135
144
|
end
|
136
145
|
|
@@ -151,7 +160,7 @@ module CarrierWave
|
|
151
160
|
end
|
152
161
|
|
153
162
|
def original_filename=(filename)
|
154
|
-
raise CarrierWave::InvalidParameter, "invalid filename"
|
163
|
+
raise CarrierWave::InvalidParameter, "invalid filename" if filename =~ CarrierWave::SanitizedFile.sanitize_regexp
|
155
164
|
@original_filename = filename
|
156
165
|
end
|
157
166
|
|
@@ -5,6 +5,8 @@ module CarrierWave
|
|
5
5
|
extend ActiveSupport::Concern
|
6
6
|
|
7
7
|
included do
|
8
|
+
class_attribute :_storage, :instance_writer => false
|
9
|
+
|
8
10
|
add_config :root
|
9
11
|
add_config :permissions
|
10
12
|
add_config :storage_engines
|
@@ -35,6 +37,8 @@ module CarrierWave
|
|
35
37
|
add_config :enable_processing
|
36
38
|
add_config :ensure_multipart_form
|
37
39
|
add_config :delete_tmp_file_after_storage
|
40
|
+
add_config :delete_cache_id_after_storage
|
41
|
+
add_config :remove_previously_stored_files_after_update
|
38
42
|
|
39
43
|
# fog
|
40
44
|
add_config :fog_attributes
|
@@ -81,19 +85,13 @@ module CarrierWave
|
|
81
85
|
# storage MyCustomStorageEngine
|
82
86
|
#
|
83
87
|
def storage(storage = nil)
|
84
|
-
if storage
|
85
|
-
|
86
|
-
elsif storage
|
87
|
-
@storage = storage
|
88
|
-
elsif @storage.nil?
|
89
|
-
# Get the storage from the superclass if there is one
|
90
|
-
@storage = superclass.storage rescue nil
|
88
|
+
if storage
|
89
|
+
self._storage = storage.is_a?(Symbol) ? eval(storage_engines[storage]) : storage
|
91
90
|
end
|
92
|
-
|
91
|
+
_storage
|
93
92
|
end
|
94
93
|
alias_method :storage=, :storage
|
95
94
|
|
96
|
-
|
97
95
|
def add_config(name)
|
98
96
|
class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
99
97
|
def self.#{name}(value=nil)
|
@@ -147,6 +145,8 @@ module CarrierWave
|
|
147
145
|
config.store_dir = 'uploads'
|
148
146
|
config.cache_dir = 'uploads/tmp'
|
149
147
|
config.delete_tmp_file_after_storage = true
|
148
|
+
config.delete_cache_id_after_storage = true
|
149
|
+
config.remove_previously_stored_files_after_update = true
|
150
150
|
config.ignore_integrity_errors = true
|
151
151
|
config.ignore_processing_errors = true
|
152
152
|
config.validate_integrity = true
|