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 +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
|