attachs 4.0.0.2 → 4.0.0.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/attachs.rb +2 -0
- data/lib/attachs/attachment.rb +5 -340
- data/lib/attachs/attachment/attributes.rb +118 -0
- data/lib/attachs/attachment/processing.rb +242 -0
- data/lib/attachs/collection.rb +1 -1
- data/lib/attachs/extensions/active_record/validations/attachment_content_type_validator.rb +5 -7
- data/lib/attachs/extensions/active_record/validations/attachment_presence_validator.rb +5 -6
- data/lib/attachs/extensions/active_record/validations/attachment_size_validator.rb +4 -5
- data/lib/attachs/extensions/active_record/validations/attachment_validator.rb +11 -3
- data/lib/attachs/locales/en.yml +1 -1
- data/lib/attachs/locales/es.yml +1 -1
- data/lib/attachs/version.rb +1 -1
- data/lib/generators/attachs/upload/templates/model.rb +4 -3
- data/test/dummy/app/models/upload.rb +5 -4
- data/test/dummy/log/test.log +4699 -0
- data/test/{validator_test.rb → validation_test.rb} +44 -28
- metadata +6 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c16c8226d22e2d772ba2f3ee5aa32f5e9b0b18e0
|
4
|
+
data.tar.gz: aa8c1e0487680a41a7a97ac4ed9d0426948e3fb1
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e0fa01842ed7f65ec104a4aed5cafa51427c432d319797b7048601ce20f7617657c0f32dafecef870bc7501a22958375c908a2039c30019922e147174ffab912
|
7
|
+
data.tar.gz: f841b2bb5bc391a640d6a46fe11232277b8cac77f66715007f2e105602a7ba00c0875fe527ec07a01498c561e61c8cd4298b53c682eadc82ec80662f05679ffb
|
data/lib/attachs.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
require 'attachs/attachment/attributes'
|
2
|
+
require 'attachs/attachment/processing'
|
1
3
|
require 'attachs/extensions/active_record/validations/attachment_validator'
|
2
4
|
require 'attachs/extensions/active_record/validations/attachment_content_type_validator'
|
3
5
|
require 'attachs/extensions/active_record/validations/attachment_presence_validator'
|
data/lib/attachs/attachment.rb
CHANGED
@@ -1,344 +1,9 @@
|
|
1
1
|
module Attachs
|
2
2
|
class Attachment
|
3
|
-
include
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
@record = record
|
9
|
-
@record_attribute = record_attribute
|
10
|
-
@options = options
|
11
|
-
@original_attributes = @attributes = normalize_attributes(attributes)
|
12
|
-
end
|
13
|
-
|
14
|
-
%i(id size filename content_type uploaded_at).each do |name|
|
15
|
-
define_method name do
|
16
|
-
attributes[name]
|
17
|
-
end
|
18
|
-
end
|
19
|
-
|
20
|
-
def basename
|
21
|
-
if filename
|
22
|
-
File.basename filename, extension
|
23
|
-
end
|
24
|
-
end
|
25
|
-
|
26
|
-
def extension
|
27
|
-
if filename
|
28
|
-
File.extname filename
|
29
|
-
end
|
30
|
-
end
|
31
|
-
|
32
|
-
def present?
|
33
|
-
filename.present? && content_type.present? && size.present?
|
34
|
-
end
|
35
|
-
|
36
|
-
def blank?
|
37
|
-
!present?
|
38
|
-
end
|
39
|
-
|
40
|
-
def persisted?
|
41
|
-
record.persisted? && paths.any? && uploaded_at
|
42
|
-
end
|
43
|
-
|
44
|
-
def changed?
|
45
|
-
@original_attributes != @attributes
|
46
|
-
end
|
47
|
-
|
48
|
-
def type
|
49
|
-
if content_type
|
50
|
-
if content_type.starts_with?('image/')
|
51
|
-
'image'
|
52
|
-
else
|
53
|
-
'file'
|
54
|
-
end
|
55
|
-
end
|
56
|
-
end
|
57
|
-
|
58
|
-
def url(style=:original)
|
59
|
-
paths = attributes[:paths]
|
60
|
-
if paths.has_key?(style)
|
61
|
-
storage.url paths[style]
|
62
|
-
elsif options.has_key?(:default_path)
|
63
|
-
template = options[:default_path]
|
64
|
-
path = generate_path(template, style)
|
65
|
-
storage.url path
|
66
|
-
end
|
67
|
-
end
|
68
|
-
|
69
|
-
def position
|
70
|
-
if options[:multiple]
|
71
|
-
attributes[:position]
|
72
|
-
end
|
73
|
-
end
|
74
|
-
|
75
|
-
def position=(value)
|
76
|
-
if options[:multiple]
|
77
|
-
attributes[:position] = value
|
78
|
-
write_record
|
79
|
-
end
|
80
|
-
end
|
81
|
-
|
82
|
-
def assign(value)
|
83
|
-
source, new_attributes = process_value(value)
|
84
|
-
if new_attributes
|
85
|
-
unless changed?
|
86
|
-
@original_attributes = attributes
|
87
|
-
end
|
88
|
-
@attributes = new_attributes
|
89
|
-
write_record
|
90
|
-
@source = source
|
91
|
-
@value = value
|
92
|
-
end
|
93
|
-
end
|
94
|
-
alias_method :value=, :assign
|
95
|
-
|
96
|
-
def _destroy=(value)
|
97
|
-
if ActiveRecord::Type::Boolean.new.type_cast_from_user(value)
|
98
|
-
assign nil
|
99
|
-
end
|
100
|
-
end
|
101
|
-
|
102
|
-
def save
|
103
|
-
if changed?
|
104
|
-
if original_attributes[:paths].any? || original_attributes[:old_paths].any?
|
105
|
-
Jobs::DeleteJob.perform_later(
|
106
|
-
original_attributes[:paths].values +
|
107
|
-
original_attributes[:old_paths]
|
108
|
-
)
|
109
|
-
end
|
110
|
-
case source.class.name
|
111
|
-
when 'Attachs::Attachment'
|
112
|
-
file = storage.get(source.paths[:original])
|
113
|
-
storage.process file, paths, styles
|
114
|
-
when 'Upload'
|
115
|
-
source.file.paths.each do |style, path|
|
116
|
-
storage.copy path, paths[style]
|
117
|
-
end
|
118
|
-
when 'ActionDispatch::Http::UploadedFile'
|
119
|
-
storage.process source, paths, styles
|
120
|
-
end
|
121
|
-
@source = @value = nil
|
122
|
-
@original_attributes = @attributes
|
123
|
-
elsif present?
|
124
|
-
if paths != generate_paths
|
125
|
-
Jobs::UpdateJob.perform_later record, record_attribute.to_s
|
126
|
-
end
|
127
|
-
end
|
128
|
-
end
|
129
|
-
|
130
|
-
def update_paths
|
131
|
-
if changed?
|
132
|
-
raise 'Save attachment before update paths'
|
133
|
-
else
|
134
|
-
new_paths = generate_paths
|
135
|
-
if paths != new_paths
|
136
|
-
new_paths.each do |style, new_path|
|
137
|
-
original_path = paths[style]
|
138
|
-
if original_path != new_path
|
139
|
-
unless storage.exists?(new_path)
|
140
|
-
storage.copy original_path, new_path
|
141
|
-
end
|
142
|
-
attributes[:paths][style] = new_path
|
143
|
-
attributes[:old_paths] |= [original_path]
|
144
|
-
end
|
145
|
-
end
|
146
|
-
update_record
|
147
|
-
end
|
148
|
-
end
|
149
|
-
end
|
150
|
-
|
151
|
-
def reprocess
|
152
|
-
if changed?
|
153
|
-
raise 'Save attachment before reprocess'
|
154
|
-
elsif present? && styles
|
155
|
-
file = storage.get(paths[:original])
|
156
|
-
paths.each do |style, path|
|
157
|
-
if storage.exists?(path)
|
158
|
-
storage.delete path
|
159
|
-
end
|
160
|
-
Rails.logger.info "Regenerating: #{style} => #{path}"
|
161
|
-
end
|
162
|
-
new_paths = generate_paths
|
163
|
-
storage.process file, new_paths, styles
|
164
|
-
attributes[:paths] = new_paths
|
165
|
-
update_record
|
166
|
-
end
|
167
|
-
end
|
168
|
-
|
169
|
-
def fix_missings
|
170
|
-
if changed?
|
171
|
-
raise 'Save attachment before fix missings'
|
172
|
-
elsif present? && styles
|
173
|
-
missings = paths.slice(:original)
|
174
|
-
paths.except(:original).each do |style, path|
|
175
|
-
unless storage.exists?(path)
|
176
|
-
missings[style] = path
|
177
|
-
Rails.logger.info "Generating: #{style} => #{path}"
|
178
|
-
end
|
179
|
-
end
|
180
|
-
if missings.size > 1
|
181
|
-
file = storage.get(paths[:original])
|
182
|
-
storage.process file, missings, styles
|
183
|
-
end
|
184
|
-
end
|
185
|
-
end
|
186
|
-
|
187
|
-
def destroy
|
188
|
-
assign nil
|
189
|
-
save
|
190
|
-
end
|
191
|
-
|
192
|
-
def method_missing(name, *args, &block)
|
193
|
-
if attributes.has_key?(name)
|
194
|
-
attributes[name]
|
195
|
-
else
|
196
|
-
super
|
197
|
-
end
|
198
|
-
end
|
199
|
-
|
200
|
-
def respond_to_missing?(name, include_private=false)
|
201
|
-
attributes.has_key?(name) || super
|
202
|
-
end
|
203
|
-
|
204
|
-
def persist
|
205
|
-
if changed? && present?
|
206
|
-
new_paths = generate_paths
|
207
|
-
if paths != new_paths
|
208
|
-
attributes[:paths] = new_paths
|
209
|
-
attributes[:uploaded_at] = Time.now
|
210
|
-
write_record
|
211
|
-
end
|
212
|
-
end
|
213
|
-
end
|
214
|
-
|
215
|
-
def unpersist
|
216
|
-
if changed? && present?
|
217
|
-
attributes[:paths] = original_attributes[:paths]
|
218
|
-
attributes[:uploaded_at] = original_attributes[:uploaded_at]
|
219
|
-
write_record
|
220
|
-
end
|
221
|
-
end
|
222
|
-
|
223
|
-
def styles
|
224
|
-
case value = options[:styles]
|
225
|
-
when Proc
|
226
|
-
value.call(record) || {}
|
227
|
-
when Hash
|
228
|
-
value
|
229
|
-
else
|
230
|
-
{}
|
231
|
-
end
|
232
|
-
end
|
233
|
-
|
234
|
-
private
|
235
|
-
|
236
|
-
def storage
|
237
|
-
Attachs.storage
|
238
|
-
end
|
239
|
-
|
240
|
-
def normalize_attributes(attributes)
|
241
|
-
attributes.reverse_merge(paths: {}, old_paths: []).deep_symbolize_keys
|
242
|
-
end
|
243
|
-
|
244
|
-
def write_record(value=nil)
|
245
|
-
unless record.destroyed?
|
246
|
-
record.send "#{record_attribute}_will_change!"
|
247
|
-
record.send :write_attribute, record_attribute, (value || raw_attributes)
|
248
|
-
end
|
249
|
-
end
|
250
|
-
|
251
|
-
def raw_attributes
|
252
|
-
if options[:multiple]
|
253
|
-
record.send(:read_attribute, record_attribute).reject{ |h| h['id'] == id }.append attributes
|
254
|
-
else
|
255
|
-
attributes
|
256
|
-
end
|
257
|
-
end
|
258
|
-
|
259
|
-
def update_record(value=nil)
|
260
|
-
unless record.destroyed?
|
261
|
-
record.update_column record_attribute, (value || raw_attributes)
|
262
|
-
end
|
263
|
-
end
|
264
|
-
|
265
|
-
def generate_path(template, style)
|
266
|
-
if path = template.try(:dup)
|
267
|
-
path.gsub! ':style', style.to_s.gsub('_', '-')
|
268
|
-
path.scan(/:[a-z_]+/).each do |token|
|
269
|
-
name = token.from(1).to_sym
|
270
|
-
path.gsub! token, interpolate(name).to_s.parameterize
|
271
|
-
end
|
272
|
-
path.squeeze! '-'
|
273
|
-
path.squeeze! '/'
|
274
|
-
path.gsub! '-.', '.'
|
275
|
-
path.gsub! '/-', '/'
|
276
|
-
path.gsub! '-/', '/'
|
277
|
-
path.sub! /^\//, ''
|
278
|
-
path
|
279
|
-
end
|
280
|
-
end
|
281
|
-
|
282
|
-
def generate_paths
|
283
|
-
template = options[:path]
|
284
|
-
paths = { original: generate_path(template, :original) }
|
285
|
-
styles.each do |style, geometry|
|
286
|
-
paths[style] = generate_path(template, style)
|
287
|
-
end
|
288
|
-
paths
|
289
|
-
end
|
290
|
-
|
291
|
-
def interpolate(name)
|
292
|
-
if %i(basename extension).include?(name)
|
293
|
-
send name
|
294
|
-
elsif name == :attribute
|
295
|
-
record_attribute
|
296
|
-
elsif attributes.except(:upload_at, :paths, :old_paths).has_key?(name)
|
297
|
-
attributes[name]
|
298
|
-
else
|
299
|
-
Attachs.interpolations.find(name).call record
|
300
|
-
end
|
301
|
-
end
|
302
|
-
|
303
|
-
def generate_id
|
304
|
-
SecureRandom.uuid.gsub '-', ''
|
305
|
-
end
|
306
|
-
|
307
|
-
def process_value(value)
|
308
|
-
case value.class.name
|
309
|
-
when 'NilClass'
|
310
|
-
[nil, {}]
|
311
|
-
when 'Attachs::Attachment'
|
312
|
-
[value, value.attributes.merge(id: generate_id)]
|
313
|
-
when 'Upload'
|
314
|
-
[value, value.file.attributes.merge(id: generate_id)]
|
315
|
-
when 'String','Fixnum','Bignum'
|
316
|
-
if Rails.configuration.cache_classes == false
|
317
|
-
Rails.application.eager_load!
|
318
|
-
end
|
319
|
-
if defined?(Upload)
|
320
|
-
upload = Upload.find(value)
|
321
|
-
[upload, upload.file.attributes.merge(id: generate_id)]
|
322
|
-
end
|
323
|
-
when 'ActionDispatch::Http::UploadedFile'
|
324
|
-
attributes = {
|
325
|
-
id: generate_id,
|
326
|
-
filename: value.original_filename,
|
327
|
-
content_type: value.content_type,
|
328
|
-
size: value.size.to_i,
|
329
|
-
uploaded_at: Time.now,
|
330
|
-
paths: {},
|
331
|
-
old_paths: []
|
332
|
-
}
|
333
|
-
if value.content_type.starts_with?('image/')
|
334
|
-
width, height = Console.find_dimensions(value.path)
|
335
|
-
attributes[:width] = width
|
336
|
-
attributes[:height] = height
|
337
|
-
attributes[:ratio] = (height.to_d / width.to_d).to_f
|
338
|
-
end
|
339
|
-
[value, attributes]
|
340
|
-
end
|
341
|
-
end
|
342
|
-
|
3
|
+
include(
|
4
|
+
ActiveModel::Validations,
|
5
|
+
Attachs::Attachment::Attributes,
|
6
|
+
Attachs::Attachment::Processing
|
7
|
+
)
|
343
8
|
end
|
344
9
|
end
|
@@ -0,0 +1,118 @@
|
|
1
|
+
module Attachs
|
2
|
+
class Attachment
|
3
|
+
module Attributes
|
4
|
+
extend ActiveSupport::Concern
|
5
|
+
|
6
|
+
attr_reader :record, :record_attribute, :options, :attributes, :value, :original_attributes, :source
|
7
|
+
|
8
|
+
def initialize(record, record_attribute, options={}, attributes={})
|
9
|
+
@record = record
|
10
|
+
@record_attribute = record_attribute
|
11
|
+
@options = options
|
12
|
+
@original_attributes = @attributes = normalize_attributes(attributes)
|
13
|
+
end
|
14
|
+
|
15
|
+
%i(id size filename content_type uploaded_at).each do |name|
|
16
|
+
define_method name do
|
17
|
+
attributes[name]
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def basename
|
22
|
+
if filename
|
23
|
+
File.basename filename, extension
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def extension
|
28
|
+
if filename
|
29
|
+
File.extname filename
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def present?
|
34
|
+
filename.present? && content_type.present? && size.present?
|
35
|
+
end
|
36
|
+
|
37
|
+
def blank?
|
38
|
+
!present?
|
39
|
+
end
|
40
|
+
|
41
|
+
def persisted?
|
42
|
+
record.persisted? && paths.any? && uploaded_at
|
43
|
+
end
|
44
|
+
|
45
|
+
def changed?
|
46
|
+
@original_attributes != @attributes
|
47
|
+
end
|
48
|
+
|
49
|
+
def type
|
50
|
+
if content_type
|
51
|
+
if content_type.starts_with?('image/')
|
52
|
+
'image'
|
53
|
+
else
|
54
|
+
'file'
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def position
|
60
|
+
if options[:multiple]
|
61
|
+
attributes[:position]
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
def position=(value)
|
66
|
+
if options[:multiple]
|
67
|
+
attributes[:position] = value
|
68
|
+
write_record
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def styles
|
73
|
+
case value = options[:styles]
|
74
|
+
when Proc
|
75
|
+
value.call(record) || {}
|
76
|
+
when Hash
|
77
|
+
value
|
78
|
+
else
|
79
|
+
{}
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
def respond_to_missing?(name, include_private=false)
|
84
|
+
attributes.has_key?(name) || super
|
85
|
+
end
|
86
|
+
|
87
|
+
def method_missing(name, *args, &block)
|
88
|
+
if attributes.has_key?(name)
|
89
|
+
attributes[name]
|
90
|
+
else
|
91
|
+
super
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
private
|
96
|
+
|
97
|
+
def normalize_attributes(attributes)
|
98
|
+
attributes.reverse_merge(paths: {}, old_paths: []).deep_symbolize_keys
|
99
|
+
end
|
100
|
+
|
101
|
+
def write_record(value=nil)
|
102
|
+
unless record.destroyed?
|
103
|
+
record.send "#{record_attribute}_will_change!"
|
104
|
+
record.send :write_attribute, record_attribute, (value || raw_attributes)
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
def raw_attributes
|
109
|
+
if options[:multiple]
|
110
|
+
record.send(:read_attribute, record_attribute).reject{ |h| h['id'] == id }.append attributes
|
111
|
+
else
|
112
|
+
attributes
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|