public
Description: Treat an ActiveRecord model as a file attachment, storing its patch, size, content type, etc.
Homepage: http://weblog.techno-weenie.net
Clone URL: git://github.com/technoweenie/attachment_fu.git
Click here to lend your support to: attachment_fu and make a donation at www.pledgie.com !
all tests pass

git-svn-id: 
http://svn.techno-weenie.net/projects/plugins/attachment_fu@2553 
567b1171-46fb-0310-a4c9-b4bef9110e78
technoweenie (author)
Wed Dec 13 22:52:18 -0800 2006
commit  f83683b55e5d03c439b9ccaca185eac515bcc909
tree    23a60b3ed945e915e180f802d3e0c1c04e712ccd
parent  54b14490e0693342b859752475f1b2bcad29ed39
...
1
 
2
3
4
...
46
47
48
 
49
50
51
52
53
54
55
56
57
58
 
 
 
 
59
60
61
62
 
 
 
 
63
64
65
...
81
82
83
 
 
 
 
 
 
 
 
 
 
 
 
84
85
86
...
93
94
95
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
96
97
98
...
152
153
154
155
156
157
158
...
160
161
162
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
163
164
165
...
171
172
173
 
 
 
 
 
174
175
176
...
193
194
195
 
 
 
196
197
198
...
1
2
3
4
5
...
47
48
49
50
51
52
53
54
 
 
 
 
 
 
55
56
57
58
59
60
61
 
62
63
64
65
66
67
68
...
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
...
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
...
186
187
188
 
189
190
191
...
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
...
224
225
226
227
228
229
230
231
232
233
234
...
251
252
253
254
255
256
257
258
259
0
@@ -1,4 +1,5 @@
0
 require File.join(File.dirname(__FILE__), 'attachment_fu', 'backends')
0
+require File.join(File.dirname(__FILE__), 'attachment_fu', 'processors')
0
 
0
 module Technoweenie # :nodoc:
0
   module AttachmentFu # :nodoc:
0
@@ -46,20 +47,22 @@ module Technoweenie # :nodoc:
0
         unless included_modules.include? InstanceMethods
0
           class_inheritable_accessor :attachment_options
0
           
0
+ options[:processor] ||= :rmagick
0
           options[:storage] ||= options[:file_system_path] ? :file_system : :db_file
0
           options[:file_system_path] ||= File.join("public", table_name)
0
           options[:file_system_path] = options[:file_system_path][1..-1] if options[:file_system_path].first == '/'
0
 
0
- ##with_options :foreign_key => 'parent_id' do |m|
0
- ## m.has_many :thumbnails, :dependent => :destroy, :class_name => options[:thumbnail_class].to_s
0
- ## m.belongs_to :parent, :class_name => self.base_class.to_s
0
- ##end
0
-
0
- ##after_save :create_attachment_thumbnails # allows thumbnails with parent_id to be created
0
+ with_options :foreign_key => 'parent_id' do |m|
0
+ m.has_many :thumbnails, :dependent => :destroy, :class_name => options[:thumbnail_class].to_s
0
+ m.belongs_to :parent, :class_name => base_class.to_s
0
+ end
0
 
0
           after_destroy :destroy_file
0
           extend ClassMethods
0
- include InstanceMethods, Technoweenie::AttachmentFu::const_get("#{options[:storage].to_s.classify}Backend")
0
+ include InstanceMethods
0
+ include Technoweenie::AttachmentFu::const_get("#{options[:storage].to_s.classify}Backend")
0
+ include Technoweenie::AttachmentFu::const_get("#{options[:processor].to_s.classify}Processor")
0
+ before_save :process_attachment
0
         end
0
         
0
         options[:content_type] = [options[:content_type]].flatten.collect { |t| t == :image ? Technoweenie::ActsAsAttachment.content_types : t }.flatten unless options[:content_type].nil?
0
@@ -81,6 +84,18 @@ module Technoweenie # :nodoc:
0
         content_types.include?(content_type)
0
       end
0
 
0
+ # Callback after an image has been resized.
0
+ #
0
+ # class Foo < ActiveRecord::Base
0
+ # acts_as_attachment
0
+ # after_resize do |record, img|
0
+ # record.aspect_ratio = img.columns.to_f / img.rows.to_f
0
+ # end
0
+ # end
0
+ def after_resize(&block)
0
+ write_inheritable_array(:after_resize, [block])
0
+ end
0
+
0
       # Callback after an attachment has been saved either to the file system or the DB.
0
       # Only called if the file has been changed, not necessarily if the record is updated.
0
       #
0
@@ -93,6 +108,25 @@ module Technoweenie # :nodoc:
0
       def after_attachment_saved(&block)
0
         write_inheritable_array(:after_attachment_saved, [block])
0
       end
0
+
0
+ # Callback before a thumbnail is saved. Use this to pass any necessary extra attributes that may be required.
0
+ #
0
+ # class Foo < ActiveRecord::Base
0
+ # acts_as_attachment
0
+ # before_thumbnail_saved do |record, thumbnail|
0
+ # ...
0
+ # end
0
+ # end
0
+ def before_thumbnail_saved(&block)
0
+ write_inheritable_array(:before_thumbnail_saved, [block])
0
+ end
0
+
0
+ # Get the thumbnail class, which is the current attachment class by default.
0
+ # Configure this with the :thumbnail_class option.
0
+ def thumbnail_class
0
+ attachment_options[:thumbnail_class] = attachment_options[:thumbnail_class].constantize unless attachment_options[:thumbnail_class].is_a?(Class)
0
+ attachment_options[:thumbnail_class]
0
+ end
0
     end
0
 
0
     module InstanceMethods
0
@@ -152,7 +186,6 @@ module Technoweenie # :nodoc:
0
         @attachment_data = nil
0
         @save_attachment = false
0
         self.size = 0
0
- return nil if data.nil?
0
 
0
         if data
0
           self.size = data.length
0
@@ -160,6 +193,26 @@ module Technoweenie # :nodoc:
0
           @attachment_data = data
0
         end
0
       end
0
+
0
+ # sets a temporary location to the asset. Use this if the file is already on the local file system
0
+ # and if you do not need to load it into memory.
0
+ def attachment_file=(file)
0
+ @attachment_file = nil
0
+ @save_attachment = false
0
+ self.size = 0
0
+
0
+ if file && File.file?(file)
0
+ file_stat = File.stat(file)
0
+ self.size = file_stat.size
0
+ @save_attachment = true
0
+ @attachment_file = file
0
+ end
0
+ end
0
+
0
+ # Retrieve the temporary attachment file data if it exists, or return nil
0
+ def attachment_file_data
0
+ (@attachment_file && File.file?(@attachment_file)) ? File.read(@attachment_file) : nil
0
+ end
0
 
0
       # Sets the content type.
0
       def content_type=(new_type)
0
@@ -171,6 +224,11 @@ module Technoweenie # :nodoc:
0
         write_attribute :filename, sanitize_filename(new_name)
0
       end
0
 
0
+ # Returns the width/height in a suitable format for the image_tag helper: (100x100)
0
+ def image_size
0
+ [width.to_s, height.to_s] * 'x'
0
+ end
0
+
0
       protected
0
         @@filename_basename_regex = /^.*(\\|\/)/
0
         @@filename_character_regex = /[^\w\.\-]/
0
@@ -193,6 +251,9 @@ module Technoweenie # :nodoc:
0
           end
0
         end
0
 
0
+ # Stub for a #process_attachment method in a processor
0
+ def process_attachment() end
0
+
0
         # Yanked from ActiveRecord::Callbacks, modified so I can pass args to the callbacks besides self.
0
         # Only accept blocks, however
0
         def callback_with_args(method, arg = self)
...
11
12
13
14
 
15
16
17
...
89
90
91
 
92
93
94
95
96
97
98
 
99
100
101
...
11
12
13
 
14
15
16
17
...
89
90
91
92
93
94
95
96
97
98
 
99
100
101
102
0
@@ -11,7 +11,7 @@ module Technoweenie # :nodoc:
0
       def attachment_data
0
         return @attachment_data if @attachment_data
0
         
0
- filename = full_filename
0
+ filename = @attachment_file || full_filename
0
         File.open(filename, 'rb') do |file|
0
           @attachment_data = file.read
0
         end if File.file?(filename)
0
@@ -89,13 +89,14 @@ module Technoweenie # :nodoc:
0
     # Methods for DB backed attachments
0
     module DbFileBackend
0
       def self.included(base) #:nodoc:
0
+ Object.const_set(:DbFile, Class.new(ActiveRecord::Base)) unless Object.const_defined?(:DbFile)
0
         base.belongs_to :db_file, :class_name => '::DbFile', :foreign_key => 'db_file_id'
0
         base.before_save :save_to_storage # so the db_file_id can be set
0
       end
0
 
0
       # Gets the attachment data
0
       def attachment_data
0
- @attachment_data ||= db_file.data
0
+ @attachment_data ||= (attachment_file_data || db_file.data)
0
       end
0
 
0
       # Destroys the file. Called in the after_destroy callback
...
1
 
2
3
4
...
 
1
2
3
4
0
@@ -1,4 +1,4 @@
0
-require File.join(File.dirname(__FILE__), 'test_helper')
0
+require File.expand_path(File.join(File.dirname(__FILE__), 'test_helper'))
0
 
0
 class BasicTest < Test::Unit::TestCase
0
   def test_should_set_default_min_size
...
34
35
36
37
38
39
 
 
 
40
41
42
...
52
53
54
55
56
57
 
 
 
58
59
60
...
34
35
36
 
 
 
37
38
39
40
41
42
...
52
53
54
 
 
 
55
56
57
58
59
60
0
@@ -34,9 +34,9 @@ end
0
 
0
 class ImageWithThumbsAttachment < Attachment
0
   has_attachment :thumbnails => { :thumb => [50, 50], :geometry => 'x50' }, :resize_to => [55,55]
0
- #after_resize do |record, img|
0
- # record.aspect_ratio = img.columns.to_f / img.rows.to_f
0
- #end
0
+ after_resize do |record, img|
0
+ record.aspect_ratio = img.columns.to_f / img.rows.to_f
0
+ end
0
 end
0
 
0
 class FileAttachment < ActiveRecord::Base
0
@@ -52,9 +52,9 @@ end
0
 class ImageWithThumbsFileAttachment < FileAttachment
0
   has_attachment :file_system_path => 'vendor/plugins/attachment_fu/test/files',
0
     :thumbnails => { :thumb => [50, 50], :geometry => 'x50' }, :resize_to => [55,55]
0
- #after_resize do |record, img|
0
- # record.aspect_ratio = img.columns.to_f / img.rows.to_f
0
- #end
0
+ after_resize do |record, img|
0
+ record.aspect_ratio = img.columns.to_f / img.rows.to_f
0
+ end
0
 end
0
 
0
 class ImageWithThumbsClassFileAttachment < FileAttachment
...
12
13
14
15
 
16
17
18
...
26
27
28
 
 
29
30
31
...
99
100
101
102
103
 
 
 
104
...
12
13
14
 
15
16
17
18
...
26
27
28
29
30
31
32
33
...
101
102
103
 
104
105
106
107
108
0
@@ -12,7 +12,7 @@ ActiveRecord::Base.establish_connection(config[ENV['DB'] || 'sqlite'])
0
 
0
 load(File.dirname(__FILE__) + "/schema.rb")
0
 
0
-Test::Unit::TestCase.fixture_path = File.dirname(__FILE__) + "/fixtures/"
0
+Test::Unit::TestCase.fixture_path = File.dirname(__FILE__) + "/fixtures"
0
 $LOAD_PATH.unshift(Test::Unit::TestCase.fixture_path)
0
 
0
 class Test::Unit::TestCase #:nodoc:
0
@@ -26,6 +26,8 @@ class Test::Unit::TestCase #:nodoc:
0
   end
0
 
0
   def setup
0
+ Attachment.saves = 0
0
+ DbFile.transaction { [Attachment, FileAttachment, OrphanAttachment, MinimalAttachment, DbFile].each { |klass| klass.delete_all } }
0
     FileUtils.rm_rf File.join(File.dirname(__FILE__), 'files')
0
     attachment_model self.class.attachment_model
0
   end
0
@@ -99,4 +101,6 @@ class Test::Unit::TestCase #:nodoc:
0
     end
0
 end
0
 
0
-require File.join(File.dirname(__FILE__), 'fixtures/attachment')
0
\ No newline at end of file
0
+require File.join(File.dirname(__FILE__), 'fixtures/attachment')
0
+require File.join(File.dirname(__FILE__), 'base_attachment_tests')
0
+require File.join(File.dirname(__FILE__), 'image_attachment_tests')
0
\ No newline at end of file
...
1
 
2
3
4
...
 
1
2
3
4
0
@@ -1,4 +1,4 @@
0
-require File.join(File.dirname(__FILE__), 'test_helper')
0
+require File.expand_path(File.join(File.dirname(__FILE__), 'test_helper'))
0
 
0
 class ValidationTest < Test::Unit::TestCase
0
   def test_should_invalidate_big_files

Comments

    No one has commented yet.