attacheable 1.3 → 1.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.
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