paperclip 3.0.4 → 3.1.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of paperclip might be problematic. Click here for more details.
- data/Appraisals +3 -3
- data/NEWS +43 -0
- data/README.md +81 -5
- data/features/basic_integration.feature +20 -2
- data/features/migration.feature +94 -0
- data/features/step_definitions/attachment_steps.rb +28 -0
- data/features/step_definitions/rails_steps.rb +19 -1
- data/features/step_definitions/web_steps.rb +3 -3
- data/gemfiles/3.0.gemfile +1 -1
- data/gemfiles/3.1.gemfile +1 -1
- data/gemfiles/3.2.gemfile +1 -1
- data/lib/generators/paperclip/templates/paperclip_migration.rb.erb +4 -8
- data/lib/paperclip.rb +2 -0
- data/lib/paperclip/attachment.rb +4 -0
- data/lib/paperclip/geometry.rb +33 -0
- data/lib/paperclip/glue.rb +2 -1
- data/lib/paperclip/io_adapters/abstract_adapter.rb +45 -0
- data/lib/paperclip/io_adapters/attachment_adapter.rb +13 -48
- data/lib/paperclip/io_adapters/file_adapter.rb +11 -61
- data/lib/paperclip/io_adapters/identity_adapter.rb +1 -1
- data/lib/paperclip/io_adapters/nil_adapter.rb +1 -1
- data/lib/paperclip/io_adapters/stringio_adapter.rb +11 -42
- data/lib/paperclip/io_adapters/uploaded_file_adapter.rb +6 -45
- data/lib/paperclip/matchers.rb +2 -2
- data/lib/paperclip/matchers/validate_attachment_content_type_matcher.rb +36 -17
- data/lib/paperclip/railtie.rb +5 -1
- data/lib/paperclip/schema.rb +59 -23
- data/lib/paperclip/storage/filesystem.rb +5 -0
- data/lib/paperclip/storage/fog.rb +36 -14
- data/lib/paperclip/storage/s3.rb +14 -16
- data/lib/paperclip/style.rb +2 -2
- data/lib/paperclip/tempfile_factory.rb +21 -0
- data/lib/paperclip/thumbnail.rb +10 -1
- data/lib/paperclip/version.rb +1 -1
- data/paperclip.gemspec +1 -1
- data/test/attachment_test.rb +56 -24
- data/test/fixtures/animated +0 -0
- data/test/fixtures/animated.unknown +0 -0
- data/test/generator_test.rb +26 -24
- data/test/geometry_test.rb +19 -0
- data/test/helper.rb +8 -0
- data/test/integration_test.rb +23 -23
- data/test/io_adapters/abstract_adapter_test.rb +44 -0
- data/test/io_adapters/attachment_adapter_test.rb +96 -34
- data/test/io_adapters/file_adapter_test.rb +13 -1
- data/test/io_adapters/stringio_adapter_test.rb +9 -10
- data/test/io_adapters/uploaded_file_adapter_test.rb +2 -1
- data/test/schema_test.rb +179 -77
- data/test/storage/filesystem_test.rb +18 -3
- data/test/storage/fog_test.rb +64 -1
- data/test/storage/s3_test.rb +38 -2
- data/test/tempfile_factory_test.rb +13 -0
- data/test/thumbnail_test.rb +45 -0
- metadata +16 -9
- data/features/support/fixtures/.boot_config.rb.swo +0 -0
- data/images.rake +0 -21
data/lib/paperclip/matchers.rb
CHANGED
@@ -41,7 +41,7 @@ module Paperclip
|
|
41
41
|
#
|
42
42
|
# class ActiveSupport::TestCase
|
43
43
|
# extend Paperclip::Shoulda::Matchers
|
44
|
-
#
|
44
|
+
#
|
45
45
|
# #...other initializers...#
|
46
46
|
# end
|
47
47
|
#
|
@@ -57,7 +57,7 @@ module Paperclip
|
|
57
57
|
# should validate_attachment_size(:avatar).
|
58
58
|
# less_than(2.megabytes)
|
59
59
|
# end
|
60
|
-
#
|
60
|
+
#
|
61
61
|
module Matchers
|
62
62
|
end
|
63
63
|
end
|
@@ -39,18 +39,10 @@ module Paperclip
|
|
39
39
|
end
|
40
40
|
|
41
41
|
def failure_message
|
42
|
-
"".tap do |
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
end
|
47
|
-
end
|
48
|
-
|
49
|
-
def negative_failure_message
|
50
|
-
"".tap do |str|
|
51
|
-
str << "Content types #{@allowed_types.join(", ")} should be rejected" if @allowed_types.present?
|
52
|
-
str << "\n" if @allowed_types.present? && @rejected_types.present?
|
53
|
-
str << "Content types #{@rejected_types.join(", ")} should be accepted by #{@attachment_name}" if @rejected_types.present?
|
42
|
+
"#{expected_attachment}\n".tap do |message|
|
43
|
+
message << accepted_types_and_failures
|
44
|
+
message << "\n\n" if @allowed_types.present? && @rejected_types.present?
|
45
|
+
message << rejected_types_and_failures
|
54
46
|
end
|
55
47
|
end
|
56
48
|
|
@@ -60,20 +52,47 @@ module Paperclip
|
|
60
52
|
|
61
53
|
protected
|
62
54
|
|
55
|
+
def accepted_types_and_failures
|
56
|
+
if @allowed_types.present?
|
57
|
+
"Accept content types: #{@allowed_types.join(", ")}\n".tap do |message|
|
58
|
+
if @missing_allowed_types.any?
|
59
|
+
message << " #{@missing_allowed_types.join(", ")} were rejected."
|
60
|
+
else
|
61
|
+
message << " All were accepted successfully."
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
def rejected_types_and_failures
|
67
|
+
if @rejected_types.present?
|
68
|
+
"Reject content types: #{@rejected_types.join(", ")}\n".tap do |message|
|
69
|
+
if @missing_rejected_types.any?
|
70
|
+
message << " #{@missing_rejected_types.join(", ")} were accepted."
|
71
|
+
else
|
72
|
+
message << " All were rejected successfully."
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
def expected_attachment
|
79
|
+
"Expected #{@attachment_name}:\n"
|
80
|
+
end
|
81
|
+
|
63
82
|
def type_allowed?(type)
|
64
|
-
|
65
|
-
file.content_type = type
|
66
|
-
@subject.attachment_for(@attachment_name).assign(file)
|
83
|
+
@subject.send("#{@attachment_name}_content_type=", type)
|
67
84
|
@subject.valid?
|
68
85
|
@subject.errors[:"#{@attachment_name}_content_type"].blank?
|
69
86
|
end
|
70
87
|
|
71
88
|
def allowed_types_allowed?
|
72
|
-
@allowed_types.
|
89
|
+
@missing_allowed_types ||= @allowed_types.reject { |type| type_allowed?(type) }
|
90
|
+
@missing_allowed_types.none?
|
73
91
|
end
|
74
92
|
|
75
93
|
def rejected_types_rejected?
|
76
|
-
|
94
|
+
@missing_rejected_types ||= @rejected_types.select { |type| type_allowed?(type) }
|
95
|
+
@missing_rejected_types.none?
|
77
96
|
end
|
78
97
|
end
|
79
98
|
end
|
data/lib/paperclip/railtie.rb
CHANGED
@@ -5,10 +5,14 @@ module Paperclip
|
|
5
5
|
require 'rails'
|
6
6
|
|
7
7
|
class Railtie < Rails::Railtie
|
8
|
-
initializer 'paperclip.insert_into_active_record' do
|
8
|
+
initializer 'paperclip.insert_into_active_record' do |app|
|
9
9
|
ActiveSupport.on_load :active_record do
|
10
10
|
Paperclip::Railtie.insert
|
11
11
|
end
|
12
|
+
|
13
|
+
if app.config.respond_to?(:paperclip_defaults)
|
14
|
+
Paperclip::Attachment.default_options.merge!(app.config.paperclip_defaults)
|
15
|
+
end
|
12
16
|
end
|
13
17
|
|
14
18
|
rake_tasks { load "tasks/paperclip.rake" }
|
data/lib/paperclip/schema.rb
CHANGED
@@ -1,39 +1,75 @@
|
|
1
|
+
require 'active_support/deprecation'
|
2
|
+
|
1
3
|
module Paperclip
|
2
|
-
# Provides
|
3
|
-
#
|
4
|
-
# In order to use this module, the target class should implement a
|
5
|
-
# +column+ method that takes the column name and type, both as symbols,
|
6
|
-
# as well as a +remove_column+ method that takes a table and column name,
|
7
|
-
# also both symbols.
|
4
|
+
# Provides helper methods that can be used in migrations.
|
8
5
|
module Schema
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
6
|
+
COLUMNS = {:file_name => :string,
|
7
|
+
:content_type => :string,
|
8
|
+
:file_size => :integer,
|
9
|
+
:updated_at => :datetime}
|
10
|
+
|
11
|
+
def self.included(base)
|
12
|
+
ActiveRecord::ConnectionAdapters::Table.send :include, TableDefinition
|
13
|
+
ActiveRecord::ConnectionAdapters::TableDefinition.send :include, TableDefinition
|
14
|
+
ActiveRecord::ConnectionAdapters::AbstractAdapter.send :include, Statements
|
13
15
|
|
14
|
-
|
15
|
-
|
16
|
-
column(column_name, column_type)
|
16
|
+
if defined?(ActiveRecord::Migration::CommandRecorder) # Rails 3.1+
|
17
|
+
ActiveRecord::Migration::CommandRecorder.send :include, CommandRecorder
|
17
18
|
end
|
18
19
|
end
|
19
20
|
|
20
|
-
|
21
|
-
|
22
|
-
|
21
|
+
module Statements
|
22
|
+
def add_attachment(table_name, *attachment_names)
|
23
|
+
raise ArgumentError, "Please specify attachment name in your add_attachment call in your migration." if attachment_names.empty?
|
24
|
+
|
25
|
+
attachment_names.each do |attachment_name|
|
26
|
+
COLUMNS.each_pair do |column_name, column_type|
|
27
|
+
add_column(table_name, "#{attachment_name}_#{column_name}", column_type)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def remove_attachment(table_name, *attachment_names)
|
33
|
+
raise ArgumentError, "Please specify attachment name in your remove_attachment call in your migration." if attachment_names.empty?
|
34
|
+
|
35
|
+
attachment_names.each do |attachment_name|
|
36
|
+
COLUMNS.each_pair do |column_name, column_type|
|
37
|
+
remove_column(table_name, "#{attachment_name}_#{column_name}", column_type)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def drop_attached_file(*args)
|
43
|
+
ActiveSupport::Deprecation.warn "Method `drop_attached_file` in the migration has been deprecated and will be replaced by `remove_attachment`."
|
44
|
+
remove_attachment(*args)
|
23
45
|
end
|
24
46
|
end
|
25
47
|
|
26
|
-
|
48
|
+
module TableDefinition
|
49
|
+
def attachment(*attachment_names)
|
50
|
+
attachment_names.each do |attachment_name|
|
51
|
+
COLUMNS.each_pair do |column_name, column_type|
|
52
|
+
column("#{attachment_name}_#{column_name}", column_type)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
27
56
|
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
yield column_name, column_type
|
57
|
+
def has_attached_file(*attachment_names)
|
58
|
+
ActiveSupport::Deprecation.warn "Method `t.has_attached_file` in the migration has been deprecated and will be replaced by `t.attachment`."
|
59
|
+
attachment(*attachment_names)
|
32
60
|
end
|
33
61
|
end
|
34
62
|
|
35
|
-
|
36
|
-
|
63
|
+
module CommandRecorder
|
64
|
+
def add_attachment(*args)
|
65
|
+
record(:add_attachment, args)
|
66
|
+
end
|
67
|
+
|
68
|
+
private
|
69
|
+
|
70
|
+
def invert_add_attachment(args)
|
71
|
+
[:remove_attachment, args]
|
72
|
+
end
|
37
73
|
end
|
38
74
|
end
|
39
75
|
end
|
@@ -36,6 +36,7 @@ module Paperclip
|
|
36
36
|
end
|
37
37
|
end
|
38
38
|
FileUtils.chmod(0666&~File.umask, path(style_name))
|
39
|
+
file.rewind
|
39
40
|
end
|
40
41
|
|
41
42
|
after_flush_writes # allows attachment to clean up temp files
|
@@ -68,5 +69,9 @@ module Paperclip
|
|
68
69
|
end
|
69
70
|
end
|
70
71
|
|
72
|
+
def copy_to_local_file(style, local_dest_path)
|
73
|
+
FileUtils.cp(path(style), local_dest_path)
|
74
|
+
end
|
75
|
+
|
71
76
|
end
|
72
77
|
end
|
@@ -90,6 +90,8 @@ module Paperclip
|
|
90
90
|
retried = true
|
91
91
|
directory.save
|
92
92
|
retry
|
93
|
+
ensure
|
94
|
+
file.rewind
|
93
95
|
end
|
94
96
|
end
|
95
97
|
|
@@ -108,27 +110,26 @@ module Paperclip
|
|
108
110
|
|
109
111
|
def public_url(style = default_style)
|
110
112
|
if @options[:fog_host]
|
111
|
-
|
112
|
-
@options[:fog_host].call(self)
|
113
|
-
else
|
114
|
-
(@options[:fog_host] =~ /%d/) ? @options[:fog_host] % (path(style).hash % 4) : @options[:fog_host]
|
115
|
-
end
|
116
|
-
|
117
|
-
"#{host}/#{path(style)}"
|
113
|
+
"#{dynamic_fog_host_for_style(style)}/#{path(style)}"
|
118
114
|
else
|
119
115
|
if fog_credentials[:provider] == 'AWS'
|
120
|
-
|
121
|
-
"https://#{@options[:fog_directory]}.s3.amazonaws.com/#{path(style)}"
|
122
|
-
else
|
123
|
-
# directory is not a valid subdomain, so use path style for access
|
124
|
-
"https://s3.amazonaws.com/#{@options[:fog_directory]}/#{path(style)}"
|
125
|
-
end
|
116
|
+
"https://#{host_name_for_directory}/#{path(style)}"
|
126
117
|
else
|
127
118
|
directory.files.new(:key => path(style)).public_url
|
128
119
|
end
|
129
120
|
end
|
130
121
|
end
|
131
122
|
|
123
|
+
def expiring_url(time = 3600, style = default_style)
|
124
|
+
expiring_url = directory.files.get_http_url(path(style), time)
|
125
|
+
|
126
|
+
if @options[:fog_host]
|
127
|
+
expiring_url.gsub!(/#{host_name_for_directory}/, dynamic_fog_host_for_style(style))
|
128
|
+
end
|
129
|
+
|
130
|
+
return expiring_url
|
131
|
+
end
|
132
|
+
|
132
133
|
def parse_credentials(creds)
|
133
134
|
creds = find_credentials(creds).stringify_keys
|
134
135
|
env = Object.const_defined?(:Rails) ? Rails.env : nil
|
@@ -148,6 +149,27 @@ module Paperclip
|
|
148
149
|
|
149
150
|
private
|
150
151
|
|
152
|
+
def dynamic_fog_host_for_style(style)
|
153
|
+
if @options[:fog_host].respond_to?(:call)
|
154
|
+
@options[:fog_host].call(self)
|
155
|
+
else
|
156
|
+
(@options[:fog_host] =~ /%d/) ? @options[:fog_host] % (path(style).hash % 4) : @options[:fog_host]
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
def host_name_for_directory
|
161
|
+
if @options[:fog_directory].to_s =~ Fog::AWS_BUCKET_SUBDOMAIN_RESTRICTON_REGEX
|
162
|
+
# This:
|
163
|
+
"#{@options[:fog_directory]}."
|
164
|
+
|
165
|
+
# Should be modified to this:
|
166
|
+
# "#{@options[:fog_directory]}.s3.amazonaws.com"
|
167
|
+
# When fog with https://github.com/fog/fog/pull/857 gets released
|
168
|
+
else
|
169
|
+
"s3.amazonaws.com/#{@options[:fog_directory]}"
|
170
|
+
end
|
171
|
+
end
|
172
|
+
|
151
173
|
def find_credentials(creds)
|
152
174
|
case creds
|
153
175
|
when File
|
@@ -175,7 +197,7 @@ module Paperclip
|
|
175
197
|
else
|
176
198
|
@options[:fog_directory]
|
177
199
|
end
|
178
|
-
|
200
|
+
|
179
201
|
@directory ||= connection.directories.new(:key => dir)
|
180
202
|
end
|
181
203
|
end
|
data/lib/paperclip/storage/s3.rb
CHANGED
@@ -61,7 +61,7 @@ module Paperclip
|
|
61
61
|
# Normally, this won't matter in the slightest and you can leave the default (which is
|
62
62
|
# path-style, or :s3_path_url). But in some cases paths don't work and you need to use
|
63
63
|
# the domain-style (:s3_domain_url). Anything else here will be treated like path-style.
|
64
|
-
#
|
64
|
+
#
|
65
65
|
# Notes:
|
66
66
|
# * The value of this option is a string, not a symbol.
|
67
67
|
# <b>right:</b> <tt>":s3_domain_url"</tt>
|
@@ -119,12 +119,12 @@ module Paperclip
|
|
119
119
|
@s3_protocol = @options[:s3_protocol] ||
|
120
120
|
Proc.new do |style, attachment|
|
121
121
|
permission = (@s3_permissions[style.to_s.to_sym] || @s3_permissions[:default])
|
122
|
-
permission = permission.call(attachment, style) if permission.
|
122
|
+
permission = permission.call(attachment, style) if permission.respond_to?(:call)
|
123
123
|
(permission == :public_read) ? 'http' : 'https'
|
124
124
|
end
|
125
125
|
@s3_metadata = @options[:s3_metadata] || {}
|
126
126
|
@s3_headers = @options[:s3_headers] || {}
|
127
|
-
@s3_headers = @s3_headers.call(instance) if @s3_headers.
|
127
|
+
@s3_headers = @s3_headers.call(instance) if @s3_headers.respond_to?(:call)
|
128
128
|
@s3_headers = (@s3_headers).inject({}) do |headers,(name,value)|
|
129
129
|
case name.to_s
|
130
130
|
when /^x-amz-meta-(.*)/i
|
@@ -180,19 +180,19 @@ module Paperclip
|
|
180
180
|
|
181
181
|
def s3_host_alias
|
182
182
|
@s3_host_alias = @options[:s3_host_alias]
|
183
|
-
@s3_host_alias = @s3_host_alias.call(self) if @s3_host_alias.
|
183
|
+
@s3_host_alias = @s3_host_alias.call(self) if @s3_host_alias.respond_to?(:call)
|
184
184
|
@s3_host_alias
|
185
185
|
end
|
186
186
|
|
187
187
|
def s3_url_options
|
188
188
|
s3_url_options = @options[:s3_url_options] || {}
|
189
|
-
s3_url_options = s3_url_options.call(instance) if s3_url_options.
|
189
|
+
s3_url_options = s3_url_options.call(instance) if s3_url_options.respond_to?(:call)
|
190
190
|
s3_url_options
|
191
191
|
end
|
192
192
|
|
193
193
|
def bucket_name
|
194
194
|
@bucket = @options[:bucket] || s3_credentials[:bucket]
|
195
|
-
@bucket = @bucket.call(self) if @bucket.
|
195
|
+
@bucket = @bucket.call(self) if @bucket.respond_to?(:call)
|
196
196
|
@bucket or raise ArgumentError, "missing required :bucket option"
|
197
197
|
end
|
198
198
|
|
@@ -249,12 +249,8 @@ module Paperclip
|
|
249
249
|
end
|
250
250
|
|
251
251
|
def set_permissions permissions
|
252
|
-
|
253
|
-
|
254
|
-
else
|
255
|
-
permissions = { :default => permissions || :public_read }
|
256
|
-
end
|
257
|
-
permissions
|
252
|
+
permissions = { :default => permissions } unless permissions.respond_to?(:merge)
|
253
|
+
permissions.merge :default => (permissions[:default] || :public_read)
|
258
254
|
end
|
259
255
|
|
260
256
|
def parse_credentials creds
|
@@ -276,15 +272,15 @@ module Paperclip
|
|
276
272
|
|
277
273
|
def s3_permissions(style = default_style)
|
278
274
|
s3_permissions = @s3_permissions[style] || @s3_permissions[:default]
|
279
|
-
s3_permissions = s3_permissions.call(self, style) if s3_permissions.
|
275
|
+
s3_permissions = s3_permissions.call(self, style) if s3_permissions.respond_to?(:call)
|
280
276
|
s3_permissions
|
281
277
|
end
|
282
278
|
|
283
279
|
def s3_protocol(style = default_style)
|
284
|
-
protocol = if @s3_protocol.
|
285
|
-
@s3_protocol.call(style, self)
|
280
|
+
protocol = if @s3_protocol.respond_to?(:call)
|
281
|
+
@s3_protocol.call(style, self).to_s
|
286
282
|
else
|
287
|
-
@s3_protocol
|
283
|
+
@s3_protocol.to_s
|
288
284
|
end
|
289
285
|
|
290
286
|
protocol = protocol.split(":").first + ":" unless protocol.empty?
|
@@ -314,6 +310,8 @@ module Paperclip
|
|
314
310
|
rescue AWS::S3::Errors::NoSuchBucket => e
|
315
311
|
create_bucket
|
316
312
|
retry
|
313
|
+
ensure
|
314
|
+
file.rewind
|
317
315
|
end
|
318
316
|
end
|
319
317
|
|
data/lib/paperclip/style.rb
CHANGED
@@ -52,12 +52,12 @@ module Paperclip
|
|
52
52
|
end
|
53
53
|
|
54
54
|
def convert_options
|
55
|
-
@convert_options.respond_to?(:call) ? @convert_options.call(attachment.instance) :
|
55
|
+
@convert_options.respond_to?(:call) ? @convert_options.call(attachment.instance) :
|
56
56
|
(@convert_options || attachment.send(:extra_options_for, name))
|
57
57
|
end
|
58
58
|
|
59
59
|
def source_file_options
|
60
|
-
@source_file_options.respond_to?(:call) ? @source_file_options.call(attachment.instance) :
|
60
|
+
@source_file_options.respond_to?(:call) ? @source_file_options.call(attachment.instance) :
|
61
61
|
(@source_file_options || attachment.send(:extra_source_file_options_for, name))
|
62
62
|
end
|
63
63
|
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module Paperclip
|
2
|
+
class TempfileFactory
|
3
|
+
|
4
|
+
ILLEGAL_FILENAME_CHARACTERS = /^~/
|
5
|
+
|
6
|
+
def generate(name)
|
7
|
+
@name = name
|
8
|
+
file = Tempfile.new([basename, extension])
|
9
|
+
file.binmode
|
10
|
+
file
|
11
|
+
end
|
12
|
+
|
13
|
+
def extension
|
14
|
+
File.extname(@name)
|
15
|
+
end
|
16
|
+
|
17
|
+
def basename
|
18
|
+
File.basename(@name, extension).gsub(ILLEGAL_FILENAME_CHARACTERS, '_')
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
data/lib/paperclip/thumbnail.rb
CHANGED
@@ -98,7 +98,16 @@ module Paperclip
|
|
98
98
|
|
99
99
|
# Return true if the format is animated
|
100
100
|
def animated?
|
101
|
-
@animated &&
|
101
|
+
@animated && (ANIMATED_FORMATS.include?(@format.to_s) || @format.blank?) && identified_as_animated?
|
102
|
+
end
|
103
|
+
|
104
|
+
# Return true if ImageMagick's +identify+ returns an animated format
|
105
|
+
def identified_as_animated?
|
106
|
+
ANIMATED_FORMATS.include? identify("-format %m :file", :file => "#{@file.path}[0]").to_s.downcase.strip
|
107
|
+
rescue Cocaine::ExitStatusError => e
|
108
|
+
raise Paperclip::Error, "There was an error running `identify` for #{@basename}" if @whiny
|
109
|
+
rescue Cocaine::CommandNotFoundError => e
|
110
|
+
raise Paperclip::Errors::CommandNotFoundError.new("Could not run the `identify` command. Please install ImageMagick.")
|
102
111
|
end
|
103
112
|
end
|
104
113
|
end
|