attacheable 1.3 → 1.4

Sign up to get free protection for your applications and to get access to all the features.
data/README CHANGED
@@ -42,7 +42,7 @@ This goes to your ActiveRecord:
42
42
 
43
43
  class Image < ActiveRecord::Base
44
44
  has_attachment :thumbnails => {:medium => "120x", :large => "800x600", :preview => "100x100"},
45
- :croppable_thumbnails => %w(preview)
45
+ :croppable_thumbnails => %w(preview), :path_prefix => 'public/assets/images', :autocreate => true
46
46
  validates_as_attachment
47
47
  end
48
48
 
@@ -54,6 +54,14 @@ In your view (view a record):
54
54
 
55
55
  <%= image_tag @image.public_filename(:preview) %>
56
56
 
57
+ Note that if you're migrating from acts_as_attachment, you may need to specify partitioned_path like this:
58
+
59
+ class Image
60
+ def partitioned_path(*args)
61
+ [id.to_s] + args
62
+ end
63
+ end
64
+
57
65
  You can use regenerate_thumbnails! method to regenerate all thumbnails for an image, like this:
58
66
 
59
67
  Image.regenerate_thumbnails!(:preview)
data/README.ru CHANGED
@@ -42,7 +42,7 @@
42
42
 
43
43
  class Image < ActiveRecord::Base
44
44
  has_attachment :thumbnails => {:medium => "120x", :large => "800x600", :preview => "100x100"},
45
- :croppable_thumbnails => %w(preview)
45
+ :croppable_thumbnails => %w(preview), :path_prefix => 'public/assets/images', :autocreate => true
46
46
  validates_as_attachment
47
47
  end
48
48
 
@@ -51,4 +51,11 @@
51
51
 
52
52
  <%= image_tag @image.public_filename(:preview) %>
53
53
 
54
+ Если мигрируете с acts_as_attachment, то полезно будет перекрыть метод partitioned_path:
55
+
56
+ class Image
57
+ def partitioned_path(*args)
58
+ [id.to_s] + args
59
+ end
60
+ end
54
61
 
data/Rakefile CHANGED
@@ -5,7 +5,7 @@ require 'rake/gempackagetask'
5
5
 
6
6
  spec = Gem::Specification.new do |s|
7
7
  s.name = 'attacheable'
8
- s.version = '1.3'
8
+ s.version = '1.4'
9
9
  s.summary = 'Library to handle image uploads'
10
10
  s.autorequire = 'attacheable'
11
11
  s.author = "Max Lapshin"
@@ -34,7 +34,7 @@ Rake::GemPackageTask.new(spec) do |package|
34
34
  end
35
35
 
36
36
 
37
- task :default => [ :test ]
37
+ #task :default => [ :test ]
38
38
 
39
39
  desc "Run all tests (requires BlueCloth, RedCloth and Rails for integration tests)"
40
40
  Rake::TestTask.new("test") { |t|
@@ -36,6 +36,7 @@ class ActiveRecord::Base
36
36
 
37
37
  options.with_indifferent_access
38
38
  options[:autocreate] ||= false
39
+ options[:force_autocreate] ||= false
39
40
  options[:thumbnails] ||= {}
40
41
  options[:thumbnails].symbolize_keys!.with_indifferent_access
41
42
  options[:croppable_thumbnails] ||= []
@@ -75,6 +76,17 @@ module Attacheable
75
76
  return File.dirname(__FILE__)+"/../.."
76
77
  end
77
78
 
79
+
80
+ def destroy_thumbnails!(thumbnail = nil)
81
+ return if filename.blank?
82
+ if thumbnail
83
+ FileUtils.rm_f(full_filename_without_creation(thumbnail))
84
+ else
85
+ to_remove = Dir["#{File.dirname(full_filename_without_creation)}/*"] - [full_filename_without_creation]
86
+ FileUtils.rm_f(to_remove)
87
+ end
88
+ end
89
+
78
90
  module ClassMethods
79
91
 
80
92
  #
@@ -83,15 +95,7 @@ module Attacheable
83
95
  def regenerate_thumbnails!(thumbnail = nil)
84
96
  connection.select_values("select id from #{table_name}").each do |object_id|
85
97
  object = find_by_id(object_id)
86
- if object && object.filename
87
- if thumbnail
88
- FileUtils.rm_f(object.full_filename_without_creation(thumbnail))
89
- else
90
- to_remove = Dir["#{File.dirname(object.full_filename_without_creation)}/*"] - [object.full_filename_without_creation]
91
- FileUtils.rm_f(to_remove)
92
- end
93
- #object.full_filename_with_creation(thumbnail)
94
- end
98
+ object.destroy_thumbnails!(thumbnail)
95
99
  end
96
100
  end
97
101
 
@@ -121,7 +125,7 @@ module Attacheable
121
125
  return "" if filename.blank?
122
126
  attachment_options[:autocreate] ? full_filename_with_creation(thumbnail) : full_filename_without_creation(thumbnail)
123
127
  end
124
-
128
+
125
129
  def full_filename_by_path(path) #:nodoc:
126
130
  return if filename.blank?
127
131
  thumbnail = path.gsub(%r((^#{Regexp.escape(attachment_basename)}_)(\w+)(#{Regexp.escape(attachment_extname)})$), '\2')
@@ -138,6 +142,14 @@ module Attacheable
138
142
  full_filename(thumbnail).gsub %r(^#{Regexp.escape(base_path)}), ''
139
143
  end
140
144
 
145
+ def image_width(thumbnail = nil)
146
+ `identify -format "%w" "#{full_filename(thumbnail)}"`.to_i
147
+ end
148
+
149
+ def image_height(thumbnail = nil)
150
+ `identify -format "%w" "#{full_filename(thumbnail)}"`.to_i
151
+ end
152
+
141
153
  protected
142
154
 
143
155
  # overrwrite this to do your own app-specific partitioning.
@@ -149,20 +161,21 @@ module Attacheable
149
161
  def create_thumbnail_if_required(thumbnail)
150
162
  thumbnail_path = full_filename_without_creation(thumbnail)
151
163
  return thumbnail_path unless thumbnail
152
- return thumbnail_path if File.exists?(thumbnail_path)
153
- return unless /image\//.match(content_type)
164
+ (return thumbnail_path if File.exists?(thumbnail_path)) unless attachment_options[:force_autocreate]
165
+ return nil unless /image\//.match(content_type)
154
166
  if attachment_options[:croppable_thumbnails].include?(thumbnail.to_sym)
155
167
  crop_and_thumbnail(thumbnail, thumbnail_path)
156
168
  else
157
169
  create_thumbnail(thumbnail, thumbnail_path)
158
170
  end
171
+ after_create_thumbnail(thumbnail, thumbnail_path) if respond_to?(:after_create_thumbnail)
159
172
  thumbnail_path
160
173
  end
161
174
 
162
175
  def create_thumbnail(thumbnail, thumbnail_path)
163
176
  return nil unless File.exists?(full_filename)
164
177
  return nil unless attachment_options[:thumbnails][thumbnail.to_sym]
165
- `convert -thumbnail #{attachment_options[:thumbnails][thumbnail.to_sym]} "#{full_filename}" "#{thumbnail_path}"`
178
+ `convert "#{full_filename}" -thumbnail "#{attachment_options[:thumbnails][thumbnail.to_sym]}" "#{thumbnail_path}"`
166
179
  thumbnail_path
167
180
  end
168
181
 
@@ -196,9 +209,7 @@ module Attacheable
196
209
 
197
210
 
198
211
  def crop_and_thumbnail(thumbnail, thumbnail_path)
199
- if !respond_to?(:width) || !respond_to?(:height)
200
- file_type, width, height = identify_image_properties(full_filename)
201
- end
212
+ file_type, width, height = identify_image_properties(full_filename)
202
213
  album_x, album_y = attachment_options[:thumbnails][thumbnail.to_sym].split("x").map &:to_i
203
214
  scale_x = width.to_f / album_x
204
215
  scale_y = height.to_f / album_y
@@ -228,8 +239,9 @@ module Attacheable
228
239
  def rename_file
229
240
  return unless @old_filename && @old_filename != full_filename
230
241
  if @save_new_attachment && File.exists?(@old_filename)
231
- FileUtils.rm @old_filename
242
+ FileUtils.rm_f(File.dirname(@old_filename)+"/*")
232
243
  elsif File.exists?(@old_filename)
244
+ (Dir[File.dirname(@old_filename)+"/*"]-[@old_filename]).each {|f| FileUtils.rm_f(f)}
233
245
  FileUtils.mv @old_filename, full_filename
234
246
  end
235
247
  @old_filename = nil
@@ -1,7 +1,7 @@
1
1
  module Attacheable
2
2
  module FileNaming
3
3
  def full_filename_with_creation(thumbnail = nil) #:nodoc:
4
- create_thumbnail_if_required(thumbnail)
4
+ create_thumbnail_if_required(thumbnail)
5
5
  end
6
6
 
7
7
  def full_filename_without_creation(thumbnail = nil) #:nodoc:
@@ -2,7 +2,7 @@ module Attacheable
2
2
  module Uploading
3
3
  def prepare_uploaded_file(file_data)
4
4
  return prepare_merb_uploaded_file(file_data) if file_data.is_a?(Hash) && file_data["tempfile"]
5
- return nil if file_data.nil? || !file_data.respond_to?(:original_filename) || !respond_to?(:filename=)
5
+ return nil if file_data.blank? || !file_data.respond_to?(:original_filename) || !respond_to?(:filename=)
6
6
 
7
7
  self.filename = file_data.original_filename
8
8
  if file_data.is_a?(StringIO)
@@ -26,6 +26,16 @@ class Image < ActiveRecord::Base
26
26
  has_attachment :thumbnails => {:medium => "120x", :large => "800x600", :preview => "100x100"},
27
27
  :croppable_thumbnails => %w(preview)
28
28
  validates_as_attachment :message => "Please upload an image file."
29
+
30
+ def callback_called
31
+ @callback_called
32
+ end
33
+
34
+ def after_create_thumbnail(thumbnail, thumbnail_path)
35
+ @callback_called = true
36
+ FileUtils.cp(thumbnail_path, thumbnail_path+".backup")
37
+ end
38
+
29
39
  end
30
40
 
31
41
  class Photo < Image
@@ -102,6 +112,33 @@ class AttacheableTest < Test::Unit::TestCase
102
112
  assert !File.exists?(File.dirname(__FILE__)+"/public/system/images/0000/0001"), "Directory should be cleaned"
103
113
  end
104
114
 
115
+ def test_file_renaming
116
+ Image.attachment_options[:autocreate] = true
117
+ input = File.open(File.dirname(__FILE__)+"/fixtures/life.jpg")
118
+ input.extend(TestUploadExtension)
119
+ assert_equal "life.jpg", input.original_filename, "should look like uploaded file"
120
+ image = Image.new(:uploaded_data => input)
121
+ assert_equal "life_medium.jpg", image.send(:thumbnail_name_for, :medium), "should generate right thumbnail filename"
122
+ assert image.save, "Image should be saved"
123
+ assert_equal "life", image.attachment_basename
124
+ assert_equal ".jpg", image.attachment_extname
125
+ assert_equal "/system/images/0000/0001/life_medium.jpg", image.public_filename(:medium)
126
+ assert File.exists?(File.dirname(__FILE__)+"/public/system/images/0000/0001/life.jpg"), "File should be saved"
127
+ assert File.exists?(File.dirname(__FILE__)+"/public/system/images/0000/0001/life_medium.jpg"), "Thumbnails should be generated on demand"
128
+
129
+ image = Image.find(1)
130
+ image.filename = "nonlife.jpg"
131
+ image.save
132
+ assert !File.exists?(File.dirname(__FILE__)+"/public/system/images/0000/0001/life.jpg"), "Old filename should not be kept"
133
+ assert !File.exists?(File.dirname(__FILE__)+"/public/system/images/0000/0001/life_medium.jpg"), "Thumbnails on renaming should be destroyd"
134
+ assert File.exists?(File.dirname(__FILE__)+"/public/system/images/0000/0001/nonlife.jpg"), "File should be saved"
135
+ assert !File.exists?(File.dirname(__FILE__)+"/public/system/images/0000/0001/nonlife_medium.jpg"), "Thumbnails on renaming should not be autocreated"
136
+
137
+ image.destroy
138
+ assert !File.exists?(File.dirname(__FILE__)+"/public/system/images/0000/0001"), "Directory should be cleaned"
139
+ end
140
+
141
+
105
142
  def test_image_with_autocreation
106
143
  Image.attachment_options[:autocreate] = true
107
144
  input = File.open(File.dirname(__FILE__)+"/fixtures/life.jpg")
@@ -193,6 +230,24 @@ class AttacheableTest < Test::Unit::TestCase
193
230
  assert !File.exists?(File.dirname(__FILE__)+"/public/system/images/0000/0001"), "Directory should be cleaned"
194
231
  end
195
232
 
233
+ def test_after_create_thumbnail
234
+ input = File.open(File.dirname(__FILE__)+"/fixtures/life.jpg")
235
+ input.extend(TestUploadExtension)
236
+ assert_equal "life.jpg", input.original_filename, "should look like uploaded file"
237
+ image = Image.new(:uploaded_data => input)
238
+ assert_equal "life_medium.jpg", image.send(:thumbnail_name_for, :medium), "should generate right thumbnail filename"
239
+ assert image.save, "Image should be saved"
240
+ assert File.exists?(File.dirname(__FILE__)+"/public/system/images/0000/0001/life.jpg"), "File should be saved"
241
+ assert !File.exists?(File.dirname(__FILE__)+"/public/system/images/0000/0001/life_medium.jpg"), "Thumbnails should not be autogenerated"
242
+ photo, data = Image.data_by_path_info(%w(0000 0001 life_medium.jpg))
243
+ assert photo, "Image should be guessed"
244
+ assert File.exists?(File.dirname(__FILE__)+"/public/system/images/0000/0001/life_medium.jpg"), "Thumbnails should be generated on demand"
245
+ assert File.exists?(File.dirname(__FILE__)+"/public/system/images/0000/0001/life_medium.jpg.backup"), "After callback should be called"
246
+ assert data, "New file should be generated"
247
+ image.destroy
248
+ assert !File.exists?(File.dirname(__FILE__)+"/public/system/images/0000/0001"), "Directory should be cleaned"
249
+ end
250
+
196
251
  def test_nil_upload
197
252
  image = Image.new(:uploaded_data => nil)
198
253
  assert image.save, "Image should be saved with empty file"
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: attacheable
3
3
  version: !ruby/object:Gem::Version
4
- version: "1.3"
4
+ version: "1.4"
5
5
  platform: ruby
6
6
  authors:
7
7
  - Max Lapshin
@@ -9,7 +9,7 @@ autorequire: attacheable
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2008-04-08 00:00:00 +04:00
12
+ date: 2008-07-30 00:00:00 +04:00
13
13
  default_executable:
14
14
  dependencies: []
15
15
 
@@ -30,6 +30,7 @@ files:
30
30
  - lib/attacheable/uploading.rb
31
31
  - lib/attacheable.rb
32
32
  - MIT-LICENSE
33
+ - pkg
33
34
  - Rakefile
34
35
  - README
35
36
  - README.ru