attacheable 1.3 → 1.4
Sign up to get free protection for your applications and to get access to all the features.
- data/README +9 -1
- data/README.ru +8 -1
- data/Rakefile +2 -2
- data/lib/attacheable.rb +29 -17
- data/lib/attacheable/file_naming.rb +1 -1
- data/lib/attacheable/uploading.rb +1 -1
- data/test/attacheable_test.rb +55 -0
- metadata +3 -2
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.
|
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|
|
data/lib/attacheable.rb
CHANGED
@@ -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
|
-
|
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]}
|
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
|
-
|
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.
|
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
|
@@ -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.
|
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)
|
data/test/attacheable_test.rb
CHANGED
@@ -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.
|
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-
|
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
|