carrierwave 2.2.2 → 3.1.0
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/README.md +180 -62
- data/lib/carrierwave/compatibility/paperclip.rb +4 -2
- data/lib/carrierwave/downloader/base.rb +28 -14
- data/lib/carrierwave/downloader/remote_file.rb +13 -10
- data/lib/carrierwave/locale/en.yml +5 -3
- data/lib/carrierwave/mount.rb +36 -50
- data/lib/carrierwave/mounter.rb +118 -50
- data/lib/carrierwave/orm/activerecord.rb +21 -62
- data/lib/carrierwave/processing/mini_magick.rb +45 -14
- data/lib/carrierwave/processing/rmagick.rb +47 -20
- data/lib/carrierwave/processing/vips.rb +43 -12
- data/lib/carrierwave/sanitized_file.rb +58 -77
- data/lib/carrierwave/storage/abstract.rb +5 -5
- data/lib/carrierwave/storage/file.rb +6 -5
- data/lib/carrierwave/storage/fog.rb +86 -65
- data/lib/carrierwave/test/matchers.rb +11 -7
- data/lib/carrierwave/uploader/cache.rb +19 -11
- data/lib/carrierwave/uploader/callbacks.rb +1 -1
- data/lib/carrierwave/uploader/configuration.rb +18 -8
- data/lib/carrierwave/uploader/{content_type_whitelist.rb → content_type_allowlist.rb} +18 -16
- data/lib/carrierwave/uploader/{content_type_blacklist.rb → content_type_denylist.rb} +20 -15
- data/lib/carrierwave/uploader/dimension.rb +66 -0
- data/lib/carrierwave/uploader/{extension_whitelist.rb → extension_allowlist.rb} +17 -15
- data/lib/carrierwave/uploader/{extension_blacklist.rb → extension_denylist.rb} +19 -14
- data/lib/carrierwave/uploader/file_size.rb +2 -2
- data/lib/carrierwave/uploader/processing.rb +45 -7
- data/lib/carrierwave/uploader/proxy.rb +16 -3
- data/lib/carrierwave/uploader/store.rb +70 -6
- data/lib/carrierwave/uploader/url.rb +1 -1
- data/lib/carrierwave/uploader/versions.rb +158 -138
- data/lib/carrierwave/uploader.rb +10 -8
- data/lib/carrierwave/utilities/file_name.rb +47 -0
- data/lib/carrierwave/utilities/uri.rb +14 -11
- data/lib/carrierwave/utilities.rb +1 -0
- data/lib/carrierwave/validations/active_model.rb +4 -6
- data/lib/carrierwave/version.rb +1 -1
- data/lib/carrierwave.rb +18 -17
- data/lib/generators/templates/{uploader.rb → uploader.rb.erb} +1 -1
- data/lib/generators/uploader_generator.rb +3 -3
- metadata +37 -63
data/lib/carrierwave/mount.rb
CHANGED
@@ -132,7 +132,7 @@ module CarrierWave
|
|
132
132
|
# end
|
133
133
|
#
|
134
134
|
def mount_uploader(column, uploader=nil, options={}, &block)
|
135
|
-
mount_base(column, uploader, options, &block)
|
135
|
+
mount_base(column, uploader, options.merge(multiple: false), &block)
|
136
136
|
|
137
137
|
mod = Module.new
|
138
138
|
include mod
|
@@ -163,21 +163,13 @@ module CarrierWave
|
|
163
163
|
end
|
164
164
|
|
165
165
|
def remote_#{column}_url=(url)
|
166
|
-
_mounter(:#{column}).remote_urls =
|
166
|
+
_mounter(:#{column}).remote_urls = url
|
167
167
|
end
|
168
168
|
|
169
169
|
def remote_#{column}_request_header=(header)
|
170
170
|
_mounter(:#{column}).remote_request_headers = [header]
|
171
171
|
end
|
172
172
|
|
173
|
-
def write_#{column}_identifier
|
174
|
-
return if frozen?
|
175
|
-
mounter = _mounter(:#{column})
|
176
|
-
|
177
|
-
mounter.clear! if mounter.remove?
|
178
|
-
write_uploader(mounter.serialization_column, mounter.identifiers.first)
|
179
|
-
end
|
180
|
-
|
181
173
|
def #{column}_identifier
|
182
174
|
_mounter(:#{column}).read_identifiers[0]
|
183
175
|
end
|
@@ -193,16 +185,6 @@ module CarrierWave
|
|
193
185
|
def #{column}_download_error
|
194
186
|
#{column}_download_errors.last
|
195
187
|
end
|
196
|
-
|
197
|
-
def store_previous_changes_for_#{column}
|
198
|
-
attribute_changes = ::ActiveRecord.version.to_s.to_f >= 5.1 ? saved_changes : changes
|
199
|
-
@_previous_changes_for_#{column} = attribute_changes[_mounter(:#{column}).serialization_column]
|
200
|
-
end
|
201
|
-
|
202
|
-
def remove_previously_stored_#{column}
|
203
|
-
before, after = @_previous_changes_for_#{column}
|
204
|
-
_mounter(:#{column}).remove_previous([before], [after])
|
205
|
-
end
|
206
188
|
RUBY
|
207
189
|
end
|
208
190
|
|
@@ -295,7 +277,7 @@ module CarrierWave
|
|
295
277
|
# end
|
296
278
|
#
|
297
279
|
def mount_uploaders(column, uploader=nil, options={}, &block)
|
298
|
-
mount_base(column, uploader, options, &block)
|
280
|
+
mount_base(column, uploader, options.merge(multiple: true), &block)
|
299
281
|
|
300
282
|
mod = Module.new
|
301
283
|
include mod
|
@@ -334,35 +316,18 @@ module CarrierWave
|
|
334
316
|
_mounter(:#{column}).remote_request_headers = headers
|
335
317
|
end
|
336
318
|
|
337
|
-
def write_#{column}_identifier
|
338
|
-
return if frozen?
|
339
|
-
mounter = _mounter(:#{column})
|
340
|
-
|
341
|
-
mounter.clear! if mounter.remove?
|
342
|
-
write_uploader(mounter.serialization_column, mounter.identifiers.presence)
|
343
|
-
end
|
344
|
-
|
345
319
|
def #{column}_identifiers
|
346
320
|
_mounter(:#{column}).read_identifiers
|
347
321
|
end
|
348
|
-
|
349
|
-
def store_previous_changes_for_#{column}
|
350
|
-
attribute_changes = ::ActiveRecord.version.to_s.to_f >= 5.1 ? saved_changes : changes
|
351
|
-
@_previous_changes_for_#{column} = attribute_changes[_mounter(:#{column}).serialization_column]
|
352
|
-
end
|
353
|
-
|
354
|
-
def remove_previously_stored_#{column}
|
355
|
-
_mounter(:#{column}).remove_previous(*@_previous_changes_for_#{column})
|
356
|
-
end
|
357
322
|
RUBY
|
358
323
|
end
|
359
324
|
|
360
|
-
|
325
|
+
private
|
361
326
|
|
362
327
|
def mount_base(column, uploader=nil, options={}, &block)
|
363
328
|
include CarrierWave::Mount::Extension
|
364
329
|
|
365
|
-
uploader = build_uploader(uploader, &block)
|
330
|
+
uploader = build_uploader(uploader, column, &block)
|
366
331
|
uploaders[column.to_sym] = uploader
|
367
332
|
uploader_options[column.to_sym] = options
|
368
333
|
|
@@ -387,6 +352,8 @@ module CarrierWave
|
|
387
352
|
|
388
353
|
def remove_#{column}!
|
389
354
|
_mounter(:#{column}).remove!
|
355
|
+
self.remove_#{column} = true
|
356
|
+
write_#{column}_identifier
|
390
357
|
end
|
391
358
|
|
392
359
|
def remove_#{column}=(value)
|
@@ -413,22 +380,36 @@ module CarrierWave
|
|
413
380
|
_mounter(:#{column}).download_errors
|
414
381
|
end
|
415
382
|
|
383
|
+
def write_#{column}_identifier
|
384
|
+
_mounter(:#{column}).write_identifier
|
385
|
+
end
|
386
|
+
|
416
387
|
def mark_remove_#{column}_false
|
417
388
|
_mounter(:#{column}).remove = false
|
418
389
|
end
|
390
|
+
|
391
|
+
def reset_previous_changes_for_#{column}
|
392
|
+
_mounter(:#{column}).reset_changes!
|
393
|
+
end
|
394
|
+
|
395
|
+
def remove_previously_stored_#{column}
|
396
|
+
_mounter(:#{column}).remove_previous
|
397
|
+
end
|
398
|
+
|
399
|
+
def remove_rolled_back_#{column}
|
400
|
+
_mounter(:#{column}).remove_added
|
401
|
+
end
|
419
402
|
RUBY
|
420
403
|
end
|
421
404
|
|
422
|
-
def build_uploader(uploader, &block)
|
423
|
-
|
405
|
+
def build_uploader(uploader, column, &block)
|
406
|
+
uploader ||= CarrierWave::Uploader::Base
|
407
|
+
return uploader unless block_given?
|
424
408
|
|
425
|
-
uploader = Class.new(uploader
|
426
|
-
const_set("
|
409
|
+
uploader = Class.new(uploader)
|
410
|
+
const_set("CarrierWave#{column.to_s.camelize}Uploader", uploader)
|
427
411
|
|
428
|
-
|
429
|
-
uploader.class_eval(&block)
|
430
|
-
uploader.recursively_apply_block_to_versions(&block)
|
431
|
-
end
|
412
|
+
uploader.class_eval(&block)
|
432
413
|
|
433
414
|
uploader
|
434
415
|
end
|
@@ -447,11 +428,16 @@ module CarrierWave
|
|
447
428
|
|
448
429
|
private
|
449
430
|
|
431
|
+
def initialize_dup(other)
|
432
|
+
@_mounters = @_mounters.dup
|
433
|
+
super
|
434
|
+
end
|
435
|
+
|
450
436
|
def _mounter(column)
|
451
437
|
# We cannot memoize in frozen objects :(
|
452
|
-
return Mounter.
|
438
|
+
return Mounter.build(self, column) if frozen?
|
453
439
|
@_mounters ||= {}
|
454
|
-
@_mounters[column] ||= Mounter.
|
440
|
+
@_mounters[column] ||= Mounter.build(self, column)
|
455
441
|
end
|
456
442
|
|
457
443
|
end # Extension
|
data/lib/carrierwave/mounter.rb
CHANGED
@@ -2,18 +2,49 @@ module CarrierWave
|
|
2
2
|
|
3
3
|
# this is an internal class, used by CarrierWave::Mount so that
|
4
4
|
# we don't pollute the model with a lot of methods.
|
5
|
-
class Mounter
|
6
|
-
|
7
|
-
|
8
|
-
|
5
|
+
class Mounter # :nodoc:
|
6
|
+
class Single < Mounter # :nodoc
|
7
|
+
def identifier
|
8
|
+
uploaders.first&.identifier
|
9
|
+
end
|
10
|
+
|
11
|
+
def temporary_identifier
|
12
|
+
temporary_identifiers.first
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
class Multiple < Mounter # :nodoc
|
17
|
+
def identifier
|
18
|
+
uploaders.map(&:identifier).presence
|
19
|
+
end
|
20
|
+
|
21
|
+
def temporary_identifier
|
22
|
+
temporary_identifiers.presence
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.build(record, column)
|
27
|
+
if record.class.uploader_options[column][:multiple]
|
28
|
+
Multiple.new(record, column)
|
29
|
+
else
|
30
|
+
Single.new(record, column)
|
31
|
+
end
|
32
|
+
end
|
9
33
|
|
10
|
-
|
34
|
+
attr_reader :column, :record, :remote_urls, :remove,
|
35
|
+
:integrity_errors, :processing_errors, :download_errors
|
36
|
+
attr_accessor :remote_request_headers, :uploader_options
|
37
|
+
|
38
|
+
def initialize(record, column)
|
11
39
|
@record = record
|
12
40
|
@column = column
|
13
41
|
@options = record.class.uploader_options[column]
|
14
42
|
@download_errors = []
|
15
43
|
@processing_errors = []
|
16
44
|
@integrity_errors = []
|
45
|
+
|
46
|
+
@removed_uploaders = []
|
47
|
+
@added_uploaders = []
|
17
48
|
end
|
18
49
|
|
19
50
|
def uploader_class
|
@@ -35,7 +66,7 @@ module CarrierWave
|
|
35
66
|
def uploaders
|
36
67
|
@uploaders ||= read_identifiers.map do |identifier|
|
37
68
|
uploader = blank_uploader
|
38
|
-
uploader.retrieve_from_store!(identifier)
|
69
|
+
uploader.retrieve_from_store!(identifier)
|
39
70
|
uploader
|
40
71
|
end
|
41
72
|
end
|
@@ -46,7 +77,7 @@ module CarrierWave
|
|
46
77
|
@uploaders = new_files.map do |new_file|
|
47
78
|
handle_error do
|
48
79
|
if new_file.is_a?(String)
|
49
|
-
if (uploader = old_uploaders.detect { |
|
80
|
+
if (uploader = old_uploaders.detect { |old_uploader| old_uploader.identifier == new_file })
|
50
81
|
uploader.staged = true
|
51
82
|
uploader
|
52
83
|
else
|
@@ -64,7 +95,9 @@ module CarrierWave
|
|
64
95
|
uploader
|
65
96
|
end
|
66
97
|
end
|
67
|
-
end.
|
98
|
+
end.reject(&:blank?)
|
99
|
+
@removed_uploaders += (old_uploaders - @uploaders)
|
100
|
+
write_temporary_identifier
|
68
101
|
end
|
69
102
|
|
70
103
|
def cache_names
|
@@ -76,33 +109,54 @@ module CarrierWave
|
|
76
109
|
return if cache_names.blank?
|
77
110
|
clear_unstaged
|
78
111
|
cache_names.each do |cache_name|
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
# ignore
|
85
|
-
end
|
112
|
+
uploader = blank_uploader
|
113
|
+
uploader.retrieve_from_cache!(cache_name)
|
114
|
+
@uploaders << uploader
|
115
|
+
rescue CarrierWave::InvalidParameter
|
116
|
+
# ignore
|
86
117
|
end
|
118
|
+
write_temporary_identifier
|
87
119
|
end
|
88
120
|
|
89
121
|
def remote_urls=(urls)
|
90
|
-
|
91
|
-
|
122
|
+
if urls.nil?
|
123
|
+
urls = []
|
124
|
+
else
|
125
|
+
urls = Array.wrap(urls).reject(&:blank?)
|
126
|
+
return if urls.blank?
|
127
|
+
end
|
128
|
+
@download_errors.clear
|
92
129
|
@remote_urls = urls
|
93
130
|
|
94
131
|
clear_unstaged
|
95
|
-
|
132
|
+
@remote_urls.zip(remote_request_headers || []) do |url, header|
|
96
133
|
handle_error do
|
97
134
|
uploader = blank_uploader
|
98
135
|
uploader.download!(url, header || {})
|
99
136
|
@uploaders << uploader
|
100
137
|
end
|
101
138
|
end
|
139
|
+
write_temporary_identifier
|
102
140
|
end
|
103
141
|
|
104
142
|
def store!
|
105
|
-
uploaders.
|
143
|
+
uploaders.each(&:store!)
|
144
|
+
end
|
145
|
+
|
146
|
+
def write_identifier
|
147
|
+
return if record.frozen?
|
148
|
+
|
149
|
+
clear! if remove?
|
150
|
+
|
151
|
+
additions, remains = uploaders.partition(&:cached?)
|
152
|
+
existing_identifiers = (@removed_uploaders + remains).map(&:identifier)
|
153
|
+
additions.each do |uploader|
|
154
|
+
uploader.deduplicate(existing_identifiers)
|
155
|
+
existing_identifiers << uploader.identifier
|
156
|
+
end
|
157
|
+
@added_uploaders += additions
|
158
|
+
|
159
|
+
record.write_uploader(serialization_column, identifier)
|
106
160
|
end
|
107
161
|
|
108
162
|
def urls(*args)
|
@@ -113,52 +167,50 @@ module CarrierWave
|
|
113
167
|
uploaders.none?(&:present?)
|
114
168
|
end
|
115
169
|
|
170
|
+
def remove=(value)
|
171
|
+
@remove = value
|
172
|
+
write_temporary_identifier
|
173
|
+
end
|
174
|
+
|
116
175
|
def remove?
|
117
|
-
remove.present? && (remove
|
176
|
+
remove.present? && (remove.to_s !~ /\A0|false$\z/)
|
118
177
|
end
|
119
178
|
|
120
179
|
def remove!
|
121
|
-
uploaders.
|
122
|
-
|
180
|
+
uploaders.each(&:remove!)
|
181
|
+
clear!
|
123
182
|
end
|
124
183
|
|
125
184
|
def clear!
|
185
|
+
@removed_uploaders += uploaders
|
186
|
+
@remove = nil
|
126
187
|
@uploaders = []
|
127
188
|
end
|
128
189
|
|
190
|
+
def reset_changes!
|
191
|
+
@removed_uploaders = []
|
192
|
+
@added_uploaders = []
|
193
|
+
end
|
194
|
+
|
129
195
|
def serialization_column
|
130
196
|
option(:mount_on) || column
|
131
197
|
end
|
132
198
|
|
133
|
-
def remove_previous
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
if value.is_a?(String)
|
140
|
-
uploader = blank_uploader
|
141
|
-
uploader.retrieve_from_store!(value)
|
142
|
-
uploader
|
143
|
-
else
|
144
|
-
value
|
145
|
-
end
|
146
|
-
end
|
147
|
-
after_paths = after.reject(&:blank?).map do |value|
|
148
|
-
if value.is_a?(String)
|
149
|
-
uploader = blank_uploader
|
150
|
-
uploader.retrieve_from_store!(value)
|
151
|
-
uploader
|
152
|
-
else
|
153
|
-
value
|
154
|
-
end.path
|
155
|
-
end
|
156
|
-
before.each do |uploader|
|
157
|
-
uploader.remove! if uploader.remove_previously_stored_files_after_update && !after_paths.include?(uploader.path)
|
158
|
-
end
|
199
|
+
def remove_previous
|
200
|
+
current_paths = uploaders.map(&:path)
|
201
|
+
@removed_uploaders
|
202
|
+
.reject {|uploader| current_paths.include?(uploader.path) }
|
203
|
+
.each { |uploader| uploader.remove! if uploader.remove_previously_stored_files_after_update }
|
204
|
+
reset_changes!
|
159
205
|
end
|
160
206
|
|
161
|
-
|
207
|
+
def remove_added
|
208
|
+
current_paths = (@removed_uploaders + uploaders.select(&:staged)).map(&:path)
|
209
|
+
@added_uploaders
|
210
|
+
.reject {|uploader| current_paths.include?(uploader.path) }
|
211
|
+
.each { |uploader| uploader.remove! }
|
212
|
+
reset_changes!
|
213
|
+
end
|
162
214
|
|
163
215
|
private
|
164
216
|
|
@@ -169,7 +221,9 @@ module CarrierWave
|
|
169
221
|
|
170
222
|
def clear_unstaged
|
171
223
|
@uploaders ||= []
|
172
|
-
@uploaders.
|
224
|
+
staged, unstaged = @uploaders.partition(&:staged)
|
225
|
+
@uploaders = staged
|
226
|
+
@removed_uploaders += unstaged
|
173
227
|
end
|
174
228
|
|
175
229
|
def handle_error
|
@@ -184,5 +238,19 @@ module CarrierWave
|
|
184
238
|
@integrity_errors << e
|
185
239
|
raise e unless option(:ignore_integrity_errors)
|
186
240
|
end
|
241
|
+
|
242
|
+
def write_temporary_identifier
|
243
|
+
return if record.frozen?
|
244
|
+
|
245
|
+
record.write_uploader(serialization_column, temporary_identifier)
|
246
|
+
end
|
247
|
+
|
248
|
+
def temporary_identifiers
|
249
|
+
if remove?
|
250
|
+
[]
|
251
|
+
else
|
252
|
+
uploaders.map { |uploader| uploader.temporary_identifier }
|
253
|
+
end
|
254
|
+
end
|
187
255
|
end # Mounter
|
188
256
|
end # CarrierWave
|
@@ -6,40 +6,6 @@ module CarrierWave
|
|
6
6
|
|
7
7
|
include CarrierWave::Mount
|
8
8
|
|
9
|
-
##
|
10
|
-
# See +CarrierWave::Mount#mount_uploader+ for documentation
|
11
|
-
#
|
12
|
-
def mount_uploader(column, uploader=nil, options={}, &block)
|
13
|
-
super
|
14
|
-
|
15
|
-
mod = Module.new
|
16
|
-
prepend mod
|
17
|
-
mod.class_eval <<-RUBY, __FILE__, __LINE__+1
|
18
|
-
def remote_#{column}_url=(url)
|
19
|
-
column = _mounter(:#{column}).serialization_column
|
20
|
-
__send__(:"\#{column}_will_change!")
|
21
|
-
super
|
22
|
-
end
|
23
|
-
RUBY
|
24
|
-
end
|
25
|
-
|
26
|
-
##
|
27
|
-
# See +CarrierWave::Mount#mount_uploaders+ for documentation
|
28
|
-
#
|
29
|
-
def mount_uploaders(column, uploader=nil, options={}, &block)
|
30
|
-
super
|
31
|
-
|
32
|
-
mod = Module.new
|
33
|
-
prepend mod
|
34
|
-
mod.class_eval <<-RUBY, __FILE__, __LINE__+1
|
35
|
-
def remote_#{column}_urls=(url)
|
36
|
-
column = _mounter(:#{column}).serialization_column
|
37
|
-
__send__(:"\#{column}_will_change!")
|
38
|
-
super
|
39
|
-
end
|
40
|
-
RUBY
|
41
|
-
end
|
42
|
-
|
43
9
|
private
|
44
10
|
|
45
11
|
def mount_base(column, uploader=nil, options={}, &block)
|
@@ -56,39 +22,23 @@ module CarrierWave
|
|
56
22
|
validates_processing_of column if uploader_option(column.to_sym, :validate_processing)
|
57
23
|
validates_download_of column if uploader_option(column.to_sym, :validate_download)
|
58
24
|
|
25
|
+
after_save :"store_#{column}!"
|
59
26
|
before_save :"write_#{column}_identifier"
|
60
|
-
|
27
|
+
if ::ActiveRecord.try(:run_after_transaction_callbacks_in_order_defined)
|
28
|
+
after_commit :"remove_previously_stored_#{column}", :on => :update
|
29
|
+
after_commit :"reset_previous_changes_for_#{column}"
|
30
|
+
after_commit :"mark_remove_#{column}_false", :on => :update
|
31
|
+
else
|
32
|
+
after_commit :"mark_remove_#{column}_false", :on => :update
|
33
|
+
after_commit :"reset_previous_changes_for_#{column}"
|
34
|
+
after_commit :"remove_previously_stored_#{column}", :on => :update
|
35
|
+
end
|
61
36
|
after_commit :"remove_#{column}!", :on => :destroy
|
62
|
-
|
63
|
-
after_commit :"remove_previously_stored_#{column}", :on => :update
|
64
|
-
after_commit :"store_#{column}!", :on => [:create, :update]
|
37
|
+
after_rollback :"remove_rolled_back_#{column}"
|
65
38
|
|
66
39
|
mod = Module.new
|
67
40
|
prepend mod
|
68
41
|
mod.class_eval <<-RUBY, __FILE__, __LINE__+1
|
69
|
-
def #{column}=(new_file)
|
70
|
-
column = _mounter(:#{column}).serialization_column
|
71
|
-
if !(new_file.blank? && __send__(:#{column}).blank?)
|
72
|
-
__send__(:"\#{column}_will_change!")
|
73
|
-
end
|
74
|
-
|
75
|
-
super
|
76
|
-
end
|
77
|
-
|
78
|
-
def remove_#{column}=(value)
|
79
|
-
column = _mounter(:#{column}).serialization_column
|
80
|
-
result = super
|
81
|
-
__send__(:"\#{column}_will_change!") if _mounter(:#{column}).remove?
|
82
|
-
result
|
83
|
-
end
|
84
|
-
|
85
|
-
def remove_#{column}!
|
86
|
-
self.remove_#{column} = true
|
87
|
-
write_#{column}_identifier
|
88
|
-
self.remove_#{column} = false
|
89
|
-
super
|
90
|
-
end
|
91
|
-
|
92
42
|
# Reset cached mounter on record reload
|
93
43
|
def reload(*)
|
94
44
|
@_mounters = nil
|
@@ -97,7 +47,16 @@ module CarrierWave
|
|
97
47
|
|
98
48
|
# Reset cached mounter on record dup
|
99
49
|
def initialize_dup(other)
|
100
|
-
|
50
|
+
old_uploaders = _mounter(:"#{column}").uploaders
|
51
|
+
super
|
52
|
+
@_mounters[:"#{column}"] = nil
|
53
|
+
# The attribute needs to be cleared to prevent it from picked up as identifier
|
54
|
+
write_attribute(_mounter(:#{column}).serialization_column, nil)
|
55
|
+
_mounter(:"#{column}").cache(old_uploaders)
|
56
|
+
end
|
57
|
+
|
58
|
+
def write_#{column}_identifier
|
59
|
+
return unless has_attribute?(_mounter(:#{column}).serialization_column)
|
101
60
|
super
|
102
61
|
end
|
103
62
|
RUBY
|
@@ -79,6 +79,10 @@ module CarrierWave
|
|
79
79
|
def resize_and_pad(width, height, background=:transparent, gravity='Center')
|
80
80
|
process :resize_and_pad => [width, height, background, gravity]
|
81
81
|
end
|
82
|
+
|
83
|
+
def crop(left, top, width, height)
|
84
|
+
process :crop => [left, top, width, height]
|
85
|
+
end
|
82
86
|
end
|
83
87
|
|
84
88
|
##
|
@@ -88,7 +92,7 @@ module CarrierWave
|
|
88
92
|
#
|
89
93
|
# === Parameters
|
90
94
|
#
|
91
|
-
# [format (#to_s)] an
|
95
|
+
# [format (#to_s)] an abbreviation of the format
|
92
96
|
#
|
93
97
|
# === Yields
|
94
98
|
#
|
@@ -210,6 +214,31 @@ module CarrierWave
|
|
210
214
|
end
|
211
215
|
end
|
212
216
|
|
217
|
+
##
|
218
|
+
# Crop the image to the contents of a box positioned at [left] and [top], with the dimensions given
|
219
|
+
# by [width] and [height]. The original image bottom/right edge is preserved if the cropping box falls
|
220
|
+
# outside the image bounds.
|
221
|
+
#
|
222
|
+
# === Parameters
|
223
|
+
#
|
224
|
+
# [left (integer)] left edge of area to extract
|
225
|
+
# [top (integer)] top edge of area to extract
|
226
|
+
# [width (Integer)] width of area to extract
|
227
|
+
# [height (Integer)] height of area to extract
|
228
|
+
#
|
229
|
+
# === Yields
|
230
|
+
#
|
231
|
+
# [MiniMagick::Image] additional manipulations to perform
|
232
|
+
#
|
233
|
+
def crop(left, top, width, height, combine_options: {}, &block)
|
234
|
+
width, height = resolve_dimensions(width, height)
|
235
|
+
|
236
|
+
minimagick!(block) do |builder|
|
237
|
+
builder.crop(left, top, width, height)
|
238
|
+
.apply(combine_options)
|
239
|
+
end
|
240
|
+
end
|
241
|
+
|
213
242
|
##
|
214
243
|
# Returns the width of the image in pixels.
|
215
244
|
#
|
@@ -262,9 +291,10 @@ module CarrierWave
|
|
262
291
|
image = yield(image)
|
263
292
|
FileUtils.mv image.path, current_path
|
264
293
|
|
265
|
-
|
294
|
+
::MiniMagick::Image.new(current_path).identify
|
266
295
|
rescue ::MiniMagick::Error, ::MiniMagick::Invalid => e
|
267
|
-
message
|
296
|
+
raise e if e.message =~ /(You must have .+ installed|is not installed|executable not found)/
|
297
|
+
message = I18n.translate(:"errors.messages.processing_error")
|
268
298
|
raise CarrierWave::ProcessingError, message
|
269
299
|
ensure
|
270
300
|
image.destroy! if image
|
@@ -306,26 +336,27 @@ module CarrierWave
|
|
306
336
|
|
307
337
|
if File.extname(result.path) != File.extname(current_path)
|
308
338
|
move_to = current_path.chomp(File.extname(current_path)) + File.extname(result.path)
|
309
|
-
file.content_type = ::
|
339
|
+
file.content_type = Marcel::Magic.by_path(move_to).try(:type)
|
310
340
|
file.move_to(move_to, permissions, directory_permissions)
|
311
341
|
end
|
312
342
|
rescue ::MiniMagick::Error, ::MiniMagick::Invalid => e
|
313
|
-
message
|
343
|
+
raise e if e.message =~ /(You must have .+ installed|is not installed|executable not found)/
|
344
|
+
message = I18n.translate(:"errors.messages.processing_error")
|
314
345
|
raise CarrierWave::ProcessingError, message
|
315
346
|
end
|
316
347
|
|
317
|
-
|
348
|
+
private
|
318
349
|
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
|
323
|
-
end
|
350
|
+
def resolve_dimensions(*dimensions)
|
351
|
+
dimensions.map do |value|
|
352
|
+
next value unless value.instance_of?(Proc)
|
353
|
+
value.arity >= 1 ? value.call(self) : value.call
|
324
354
|
end
|
355
|
+
end
|
325
356
|
|
326
|
-
|
327
|
-
|
328
|
-
|
357
|
+
def mini_magick_image
|
358
|
+
::MiniMagick::Image.read(read)
|
359
|
+
end
|
329
360
|
|
330
361
|
end # MiniMagick
|
331
362
|
end # CarrierWave
|