popel-attachment_fu 1.0.4

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.
Files changed (33) hide show
  1. data/README +200 -0
  2. data/VERSION.yml +4 -0
  3. data/lib/geometry.rb +93 -0
  4. data/lib/technoweenie/attachment_fu.rb +528 -0
  5. data/lib/technoweenie/attachment_fu/backends/db_file_backend.rb +39 -0
  6. data/lib/technoweenie/attachment_fu/backends/file_system_backend.rb +126 -0
  7. data/lib/technoweenie/attachment_fu/backends/s3_backend.rb +394 -0
  8. data/lib/technoweenie/attachment_fu/processors/core_image_processor.rb +59 -0
  9. data/lib/technoweenie/attachment_fu/processors/gd2_processor.rb +54 -0
  10. data/lib/technoweenie/attachment_fu/processors/image_science_processor.rb +61 -0
  11. data/lib/technoweenie/attachment_fu/processors/mini_magick_processor.rb +132 -0
  12. data/lib/technoweenie/attachment_fu/processors/rmagick_processor.rb +57 -0
  13. data/test/backends/db_file_test.rb +16 -0
  14. data/test/backends/file_system_test.rb +143 -0
  15. data/test/backends/remote/s3_test.rb +119 -0
  16. data/test/base_attachment_tests.rb +77 -0
  17. data/test/basic_test.rb +70 -0
  18. data/test/database.yml +18 -0
  19. data/test/extra_attachment_test.rb +67 -0
  20. data/test/fixtures/attachment.rb +215 -0
  21. data/test/fixtures/files/fake/rails.png +0 -0
  22. data/test/fixtures/files/foo.txt +1 -0
  23. data/test/fixtures/files/rails.png +0 -0
  24. data/test/geometry_test.rb +108 -0
  25. data/test/processors/core_image_test.rb +37 -0
  26. data/test/processors/gd2_test.rb +31 -0
  27. data/test/processors/image_science_test.rb +31 -0
  28. data/test/processors/mini_magick_test.rb +103 -0
  29. data/test/processors/rmagick_test.rb +255 -0
  30. data/test/schema.rb +121 -0
  31. data/test/test_helper.rb +150 -0
  32. data/test/validation_test.rb +55 -0
  33. metadata +95 -0
@@ -0,0 +1,119 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__), '..', '..', 'test_helper'))
2
+ require 'net/http'
3
+
4
+ class S3Test < Test::Unit::TestCase
5
+ def self.test_S3?
6
+ true unless ENV["TEST_S3"] == "false"
7
+ end
8
+
9
+ if test_S3? && File.exist?(File.join(File.dirname(__FILE__), '../../amazon_s3.yml'))
10
+ include BaseAttachmentTests
11
+ attachment_model S3Attachment
12
+
13
+ def test_should_create_correct_bucket_name(klass = S3Attachment)
14
+ attachment_model klass
15
+ attachment = upload_file :filename => '/files/rails.png'
16
+ assert_equal attachment.s3_config[:bucket_name], attachment.bucket_name
17
+ end
18
+
19
+ test_against_subclass :test_should_create_correct_bucket_name, S3Attachment
20
+
21
+ def test_should_create_default_path_prefix(klass = S3Attachment)
22
+ attachment_model klass
23
+ attachment = upload_file :filename => '/files/rails.png'
24
+ assert_equal File.join(attachment_model.table_name, attachment.attachment_path_id), attachment.base_path
25
+ end
26
+
27
+ test_against_subclass :test_should_create_default_path_prefix, S3Attachment
28
+
29
+ def test_should_create_custom_path_prefix(klass = S3WithPathPrefixAttachment)
30
+ attachment_model klass
31
+ attachment = upload_file :filename => '/files/rails.png'
32
+ assert_equal File.join('some/custom/path/prefix', attachment.attachment_path_id), attachment.base_path
33
+ end
34
+
35
+ test_against_subclass :test_should_create_custom_path_prefix, S3WithPathPrefixAttachment
36
+
37
+ def test_should_create_valid_url(klass = S3Attachment)
38
+ attachment_model klass
39
+ attachment = upload_file :filename => '/files/rails.png'
40
+ assert_equal "#{s3_protocol}#{s3_hostname}#{s3_port_string}/#{attachment.bucket_name}/#{attachment.full_filename}", attachment.s3_url
41
+ end
42
+
43
+ test_against_subclass :test_should_create_valid_url, S3Attachment
44
+
45
+ def test_should_create_authenticated_url(klass = S3Attachment)
46
+ attachment_model klass
47
+ attachment = upload_file :filename => '/files/rails.png'
48
+ assert_match /^http.+AWSAccessKeyId.+Expires.+Signature.+/, attachment.authenticated_s3_url(:use_ssl => true)
49
+ end
50
+
51
+ test_against_subclass :test_should_create_authenticated_url, S3Attachment
52
+
53
+ def test_should_create_authenticated_url_for_thumbnail(klass = S3Attachment)
54
+ attachment_model klass
55
+ attachment = upload_file :filename => '/files/rails.png'
56
+ ['large', :large].each do |thumbnail|
57
+ assert_match(
58
+ /^http.+rails_large\.png.+AWSAccessKeyId.+Expires.+Signature/,
59
+ attachment.authenticated_s3_url(thumbnail),
60
+ "authenticated_s3_url failed with #{thumbnail.class} parameter"
61
+ )
62
+ end
63
+ end
64
+
65
+ def test_should_save_attachment(klass = S3Attachment)
66
+ attachment_model klass
67
+ assert_created do
68
+ attachment = upload_file :filename => '/files/rails.png'
69
+ assert_valid attachment
70
+ assert attachment.image?
71
+ assert !attachment.size.zero?
72
+ assert_kind_of Net::HTTPOK, http_response_for(attachment.s3_url)
73
+ end
74
+ end
75
+
76
+ test_against_subclass :test_should_save_attachment, S3Attachment
77
+
78
+ def test_should_delete_attachment_from_s3_when_attachment_record_destroyed(klass = S3Attachment)
79
+ attachment_model klass
80
+ attachment = upload_file :filename => '/files/rails.png'
81
+
82
+ urls = [attachment.s3_url] + attachment.thumbnails.collect(&:s3_url)
83
+
84
+ urls.each {|url| assert_kind_of Net::HTTPOK, http_response_for(url) }
85
+ attachment.destroy
86
+ urls.each do |url|
87
+ begin
88
+ http_response_for(url)
89
+ rescue Net::HTTPForbidden, Net::HTTPNotFound
90
+ nil
91
+ end
92
+ end
93
+ end
94
+
95
+ test_against_subclass :test_should_delete_attachment_from_s3_when_attachment_record_destroyed, S3Attachment
96
+
97
+ protected
98
+ def http_response_for(url)
99
+ url = URI.parse(url)
100
+ Net::HTTP.start(url.host, url.port) {|http| http.request_head(url.path) }
101
+ end
102
+
103
+ def s3_protocol
104
+ Technoweenie::AttachmentFu::Backends::S3Backend.protocol
105
+ end
106
+
107
+ def s3_hostname
108
+ Technoweenie::AttachmentFu::Backends::S3Backend.hostname
109
+ end
110
+
111
+ def s3_port_string
112
+ Technoweenie::AttachmentFu::Backends::S3Backend.port_string
113
+ end
114
+ else
115
+ def test_flunk_s3
116
+ puts "s3 config file not loaded, tests not running"
117
+ end
118
+ end
119
+ end
@@ -0,0 +1,77 @@
1
+ module BaseAttachmentTests
2
+ def test_should_create_file_from_uploaded_file
3
+ assert_created do
4
+ attachment = upload_file :filename => '/files/foo.txt'
5
+ assert_valid attachment
6
+ assert !attachment.db_file.new_record? if attachment.respond_to?(:db_file)
7
+ assert attachment.image?
8
+ assert !attachment.size.zero?
9
+ #assert_equal 3, attachment.size
10
+ assert_nil attachment.width
11
+ assert_nil attachment.height
12
+ end
13
+ end
14
+
15
+ def test_should_create_file_from_merb_temp_file
16
+ assert_created do
17
+ attachment = upload_merb_file :filename => '/files/foo.txt'
18
+ assert_valid attachment
19
+ assert !attachment.db_file.new_record? if attachment.respond_to?(:db_file)
20
+ assert attachment.image?
21
+ assert !attachment.size.zero?
22
+ #assert_equal 3, attachment.size
23
+ assert_nil attachment.width
24
+ assert_nil attachment.height
25
+ end
26
+ end
27
+
28
+ def test_reassign_attribute_data
29
+ assert_created 1 do
30
+ attachment = upload_file :filename => '/files/rails.png'
31
+ assert_valid attachment
32
+ assert attachment.size > 0, "no data was set"
33
+
34
+ attachment.set_temp_data 'wtf'
35
+ assert attachment.save_attachment?
36
+ attachment.save!
37
+
38
+ assert_equal 'wtf', attachment_model.find(attachment.id).send(:current_data)
39
+ end
40
+ end
41
+
42
+ def test_no_reassign_attribute_data_on_nil
43
+ assert_created 1 do
44
+ attachment = upload_file :filename => '/files/rails.png'
45
+ assert_valid attachment
46
+ assert attachment.size > 0, "no data was set"
47
+
48
+ attachment.set_temp_data nil
49
+ assert !attachment.save_attachment?
50
+ end
51
+ end
52
+
53
+ def test_should_overwrite_old_contents_when_updating
54
+ attachment = upload_file :filename => '/files/rails.png'
55
+ assert_not_created do # no new db_file records
56
+ use_temp_file 'files/rails.png' do |file|
57
+ attachment.filename = 'rails2.png'
58
+ attachment.temp_paths.unshift File.join(fixture_path, file)
59
+ attachment.save!
60
+ end
61
+ end
62
+ end
63
+
64
+ def test_should_save_without_updating_file
65
+ attachment = upload_file :filename => '/files/foo.txt'
66
+ assert_valid attachment
67
+ assert !attachment.save_attachment?
68
+ assert_nothing_raised { attachment.save! }
69
+ end
70
+
71
+ def test_should_handle_nil_file_upload
72
+ attachment = attachment_model.create :uploaded_data => ''
73
+ assert_raise ActiveRecord::RecordInvalid do
74
+ attachment.save!
75
+ end
76
+ end
77
+ end
@@ -0,0 +1,70 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__), 'test_helper'))
2
+
3
+ class BasicTest < Test::Unit::TestCase
4
+ def test_should_set_default_min_size
5
+ assert_equal 1, Attachment.attachment_options[:min_size]
6
+ end
7
+
8
+ def test_should_set_default_max_size
9
+ assert_equal 1.megabyte, Attachment.attachment_options[:max_size]
10
+ end
11
+
12
+ def test_should_set_default_size
13
+ assert_equal (1..1.megabyte), Attachment.attachment_options[:size]
14
+ end
15
+
16
+ def test_should_set_default_thumbnails_option
17
+ assert_equal Hash.new, Attachment.attachment_options[:thumbnails]
18
+ end
19
+
20
+ def test_should_set_default_thumbnail_class
21
+ assert_equal Attachment, Attachment.attachment_options[:thumbnail_class]
22
+ end
23
+
24
+ def test_should_normalize_content_types_to_array
25
+ assert_equal %w(pdf), PdfAttachment.attachment_options[:content_type]
26
+ assert_equal %w(pdf doc txt), DocAttachment.attachment_options[:content_type]
27
+ assert_equal Technoweenie::AttachmentFu.content_types, ImageAttachment.attachment_options[:content_type]
28
+ assert_equal ['pdf'] + Technoweenie::AttachmentFu.content_types, ImageOrPdfAttachment.attachment_options[:content_type]
29
+ end
30
+
31
+ def test_should_sanitize_content_type
32
+ @attachment = Attachment.new :content_type => ' foo '
33
+ assert_equal 'foo', @attachment.content_type
34
+ end
35
+
36
+ def test_should_sanitize_filenames
37
+ @attachment = Attachment.new :filename => 'blah/foo.bar'
38
+ assert_equal 'foo.bar', @attachment.filename
39
+
40
+ @attachment.filename = 'blah\\foo.bar'
41
+ assert_equal 'foo.bar', @attachment.filename
42
+
43
+ @attachment.filename = 'f o!O-.bar'
44
+ assert_equal 'f_o_O-.bar', @attachment.filename
45
+
46
+ @attachment.filename = 'sheeps_says_bææ'
47
+ assert_equal 'sheeps_says_b__', @attachment.filename
48
+
49
+ @attachment.filename = nil
50
+ assert_nil @attachment.filename
51
+ end
52
+
53
+ def test_should_convert_thumbnail_name
54
+ @attachment = FileAttachment.new :filename => 'foo.bar'
55
+ assert_equal 'foo.bar', @attachment.thumbnail_name_for(nil)
56
+ assert_equal 'foo.bar', @attachment.thumbnail_name_for('')
57
+ assert_equal 'foo_blah.bar', @attachment.thumbnail_name_for(:blah)
58
+ assert_equal 'foo_blah.blah.bar', @attachment.thumbnail_name_for('blah.blah')
59
+
60
+ @attachment.filename = 'foo.bar.baz'
61
+ assert_equal 'foo.bar_blah.baz', @attachment.thumbnail_name_for(:blah)
62
+ end
63
+
64
+ def test_should_require_valid_thumbnails_option
65
+ klass = Class.new(ActiveRecord::Base)
66
+ assert_raise ArgumentError do
67
+ klass.has_attachment :thumbnails => []
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,18 @@
1
+ sqlite:
2
+ :adapter: sqlite
3
+ :dbfile: attachment_fu_plugin.sqlite.db
4
+ sqlite3:
5
+ :adapter: sqlite3
6
+ :dbfile: attachment_fu_plugin.sqlite3.db
7
+ postgresql:
8
+ :adapter: postgresql
9
+ :username: postgres
10
+ :password: postgres
11
+ :database: attachment_fu_plugin_test
12
+ :min_messages: ERROR
13
+ mysql:
14
+ :adapter: mysql
15
+ :host: localhost
16
+ :username: rails
17
+ :password:
18
+ :database: attachment_fu_plugin_test
@@ -0,0 +1,67 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__), 'test_helper'))
2
+
3
+ class OrphanAttachmentTest < Test::Unit::TestCase
4
+ include BaseAttachmentTests
5
+ attachment_model OrphanAttachment
6
+
7
+ def test_should_create_image_from_uploaded_file
8
+ assert_created do
9
+ attachment = upload_file :filename => '/files/rails.png'
10
+ assert_valid attachment
11
+ assert !attachment.db_file.new_record? if attachment.respond_to?(:db_file)
12
+ assert attachment.image?
13
+ assert !attachment.size.zero?
14
+ end
15
+ end
16
+
17
+ def test_should_create_file_from_uploaded_file
18
+ assert_created do
19
+ attachment = upload_file :filename => '/files/foo.txt'
20
+ assert_valid attachment
21
+ assert !attachment.db_file.new_record? if attachment.respond_to?(:db_file)
22
+ assert attachment.image?
23
+ assert !attachment.size.zero?
24
+ end
25
+ end
26
+
27
+ def test_should_create_file_from_merb_temp_file
28
+ assert_created do
29
+ attachment = upload_merb_file :filename => '/files/foo.txt'
30
+ assert_valid attachment
31
+ assert !attachment.db_file.new_record? if attachment.respond_to?(:db_file)
32
+ assert attachment.image?
33
+ assert !attachment.size.zero?
34
+ end
35
+ end
36
+
37
+ def test_should_create_image_from_uploaded_file_with_custom_content_type
38
+ assert_created do
39
+ attachment = upload_file :content_type => 'foo/bar', :filename => '/files/rails.png'
40
+ assert_valid attachment
41
+ assert !attachment.image?
42
+ assert !attachment.db_file.new_record? if attachment.respond_to?(:db_file)
43
+ assert !attachment.size.zero?
44
+ #assert_equal 1784, attachment.size
45
+ end
46
+ end
47
+
48
+ def test_should_create_thumbnail
49
+ attachment = upload_file :filename => '/files/rails.png'
50
+
51
+ assert_raise Technoweenie::AttachmentFu::ThumbnailError do
52
+ attachment.create_or_update_thumbnail(attachment.create_temp_file, 'thumb', 50, 50)
53
+ end
54
+ end
55
+
56
+ def test_should_create_thumbnail_with_geometry_string
57
+ attachment = upload_file :filename => '/files/rails.png'
58
+
59
+ assert_raise Technoweenie::AttachmentFu::ThumbnailError do
60
+ attachment.create_or_update_thumbnail(attachment.create_temp_file, 'thumb', 'x50')
61
+ end
62
+ end
63
+ end
64
+
65
+ class MinimalAttachmentTest < OrphanAttachmentTest
66
+ attachment_model MinimalAttachment
67
+ end
@@ -0,0 +1,215 @@
1
+ class Attachment < ActiveRecord::Base
2
+ @@saves = 0
3
+ cattr_accessor :saves
4
+ has_attachment :processor => :rmagick
5
+ validates_as_attachment
6
+ after_attachment_saved do |record|
7
+ self.saves += 1
8
+ end
9
+ end
10
+
11
+ class SmallAttachment < Attachment
12
+ has_attachment :max_size => 1.kilobyte
13
+ end
14
+
15
+ class BigAttachment < Attachment
16
+ has_attachment :size => 1.megabyte..2.megabytes
17
+ end
18
+
19
+ class PdfAttachment < Attachment
20
+ has_attachment :content_type => 'pdf'
21
+ end
22
+
23
+ class DocAttachment < Attachment
24
+ has_attachment :content_type => %w(pdf doc txt)
25
+ end
26
+
27
+ class ImageAttachment < Attachment
28
+ has_attachment :content_type => :image, :resize_to => [50,50]
29
+ end
30
+
31
+ class ImageOrPdfAttachment < Attachment
32
+ has_attachment :content_type => ['pdf', :image], :resize_to => 'x50'
33
+ end
34
+
35
+ class ImageWithThumbsAttachment < Attachment
36
+ has_attachment :thumbnails => { :thumb => [50, 50], :geometry => 'x50' }, :resize_to => [55,55]
37
+ after_resize do |record, img|
38
+ # record.aspect_ratio = img.columns.to_f / img.rows.to_f
39
+ end
40
+ end
41
+
42
+ class FileAttachment < ActiveRecord::Base
43
+ has_attachment :path_prefix => 'vendor/plugins/attachment_fu/test/files', :processor => :rmagick
44
+ validates_as_attachment
45
+ end
46
+
47
+ class FileAttachmentWithStringId < ActiveRecord::Base
48
+ set_table_name 'file_attachments_with_string_id'
49
+ has_attachment :path_prefix => 'vendor/plugins/attachment_fu/test/files', :processor => :rmagick
50
+ validates_as_attachment
51
+
52
+ before_validation :auto_generate_id
53
+ before_save :auto_generate_id
54
+ @@last_id = 0
55
+
56
+ private
57
+ def auto_generate_id
58
+ @@last_id += 1
59
+ self.id = "id_#{@@last_id}"
60
+ end
61
+ end
62
+
63
+ class FileAttachmentWithUuid < ActiveRecord::Base
64
+ set_table_name 'file_attachments_with_string_id'
65
+ has_attachment :path_prefix => 'vendor/plugins/attachment_fu/test/files', :processor => :rmagick, :uuid_primary_key => true
66
+ validates_as_attachment
67
+
68
+ before_validation :auto_generate_id
69
+ before_save :auto_generate_id
70
+ @@last_id = 0
71
+
72
+ private
73
+ def auto_generate_id
74
+ @@last_id += 1
75
+ self.id = "%0127dx" % @@last_id
76
+ end
77
+ end
78
+
79
+ class ImageFileAttachment < FileAttachment
80
+ has_attachment :path_prefix => 'vendor/plugins/attachment_fu/test/files',
81
+ :content_type => :image, :resize_to => [50,50]
82
+ end
83
+
84
+ class ImageWithThumbsFileAttachment < FileAttachment
85
+ has_attachment :path_prefix => 'vendor/plugins/attachment_fu/test/files',
86
+ :thumbnails => { :thumb => [50, 50], :geometry => 'x50' }, :resize_to => [55,55]
87
+ after_resize do |record, img|
88
+ # record.aspect_ratio = img.columns.to_f / img.rows.to_f
89
+ end
90
+ end
91
+
92
+ class ImageWithThumbsClassFileAttachment < FileAttachment
93
+ # use file_system_path to test backwards compatibility
94
+ has_attachment :file_system_path => 'vendor/plugins/attachment_fu/test/files',
95
+ :thumbnails => { :thumb => [50, 50] }, :resize_to => [55,55],
96
+ :thumbnail_class => 'ImageThumbnail'
97
+ end
98
+
99
+ class ImageThumbnail < FileAttachment
100
+ has_attachment :path_prefix => 'vendor/plugins/attachment_fu/test/files/thumbnails'
101
+ end
102
+
103
+ # no parent
104
+ class OrphanAttachment < ActiveRecord::Base
105
+ has_attachment :processor => :rmagick
106
+ validates_as_attachment
107
+ end
108
+
109
+ # no filename, no size, no content_type
110
+ class MinimalAttachment < ActiveRecord::Base
111
+ has_attachment :path_prefix => 'vendor/plugins/attachment_fu/test/files', :processor => :rmagick
112
+ validates_as_attachment
113
+
114
+ def filename
115
+ "#{id}.file"
116
+ end
117
+ end
118
+
119
+ begin
120
+ class ImageScienceAttachment < ActiveRecord::Base
121
+ has_attachment :path_prefix => 'vendor/plugins/attachment_fu/test/files',
122
+ :processor => :image_science, :thumbnails => { :thumb => [50, 51], :geometry => '31>' }, :resize_to => 55
123
+ end
124
+ rescue MissingSourceFile
125
+ puts $!.message
126
+ puts "no ImageScience"
127
+ end
128
+
129
+ begin
130
+ class CoreImageAttachment < ActiveRecord::Base
131
+ has_attachment :path_prefix => 'vendor/plugins/attachment_fu/test/files',
132
+ :processor => :core_image, :thumbnails => { :thumb => [50, 51], :geometry => '31>' }, :resize_to => 55
133
+ end
134
+ rescue MissingSourceFile
135
+ puts $!.message
136
+ puts "no CoreImage"
137
+ end
138
+
139
+ begin
140
+ class MiniMagickAttachment < ActiveRecord::Base
141
+ has_attachment :path_prefix => 'vendor/plugins/attachment_fu/test/files',
142
+ :processor => :mini_magick, :thumbnails => { :thumb => [50, 51], :geometry => '31>' }, :resize_to => 55
143
+ end
144
+ rescue MissingSourceFile
145
+ puts $!.message
146
+ puts "no Mini Magick"
147
+ end
148
+
149
+ begin
150
+ class GD2Attachment < ActiveRecord::Base
151
+ has_attachment :path_prefix => 'vendor/plugins/attachment_fu/test/files',
152
+ :processor => :gd2, :thumbnails => { :thumb => [50, 51], :geometry => '31>' }, :resize_to => 55
153
+ end
154
+ rescue MissingSourceFile
155
+ puts $!.message
156
+ puts "no GD2"
157
+ end
158
+
159
+
160
+ begin
161
+ class MiniMagickAttachment < ActiveRecord::Base
162
+ has_attachment :path_prefix => 'vendor/plugins/attachment_fu/test/files',
163
+ :processor => :mini_magick, :thumbnails => { :thumb => [50, 51], :geometry => '31>' }, :resize_to => 55
164
+ end
165
+ class ImageThumbnailCrop < MiniMagickAttachment
166
+ has_attachment :path_prefix => 'vendor/plugins/attachment_fu/test/files',
167
+ :thumbnails => { :square => "50x50c", :vertical => "30x60c", :horizontal => "60x30c"}
168
+
169
+ # TODO this is a bad duplication, this method is in the MiniMagick Processor
170
+ def self.calculate_offset(image_width,image_height,image_aspect,thumb_width,thumb_height,thumb_aspect)
171
+ # only crop if image is not smaller in both dimensions
172
+
173
+ # special cases, image smaller in one dimension then thumbsize
174
+ if image_width < thumb_width
175
+ offset = (image_height / 2) - (thumb_height / 2)
176
+ command = "#{image_width}x#{thumb_height}+0+#{offset}"
177
+ elsif image_height < thumb_height
178
+ offset = (image_width / 2) - (thumb_width / 2)
179
+ command = "#{thumb_width}x#{image_height}+#{offset}+0"
180
+
181
+ # normal thumbnail generation
182
+ # calculate height and offset y, width is fixed
183
+ elsif (image_aspect <= thumb_aspect or image_width < thumb_width) and image_height > thumb_height
184
+ height = image_width / thumb_aspect
185
+ offset = (image_height / 2) - (height / 2)
186
+ command = "#{image_width}x#{height}+0+#{offset}"
187
+ # calculate width and offset x, height is fixed
188
+ else
189
+ width = image_height * thumb_aspect
190
+ offset = (image_width / 2) - (width / 2)
191
+ command = "#{width}x#{image_height}+#{offset}+0"
192
+ end
193
+ # crop image
194
+ command
195
+ end
196
+ end
197
+
198
+ rescue MissingSourceFile
199
+ end
200
+
201
+
202
+
203
+ begin
204
+ class S3Attachment < ActiveRecord::Base
205
+ has_attachment :storage => :s3, :processor => :rmagick, :s3_config_path => File.join(File.dirname(__FILE__), '../amazon_s3.yml')
206
+ validates_as_attachment
207
+ end
208
+
209
+ class S3WithPathPrefixAttachment < S3Attachment
210
+ has_attachment :storage => :s3, :path_prefix => 'some/custom/path/prefix', :processor => :rmagick
211
+ validates_as_attachment
212
+ end
213
+ rescue
214
+ puts "S3 error: #{$!}"
215
+ end