better_record 0.15.2 → 0.16.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/app/jobs/active_storage/purge_job.rb +13 -0
- data/app/models/better_record/attachment_validation.rb +36 -0
- data/app/models/better_record/model_concerns/has_validated_avatar.rb +80 -28
- data/db/migrate/20181228204403_create_better_record_attachment_validations.rb +15 -0
- data/lib/better_record/version.rb +1 -1
- metadata +4 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 669acb9b867dcb30b92fbe9d4d147f97c60862aedebd1a9a5f9319577f262b17
|
4
|
+
data.tar.gz: fea7a77007c6279d2c0ad4b9845f22579b9ff608e54e49f306d36da4d68198f4
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 283448eb2be733d810ffdb8bfcfcdb1ec0471983729da9529e4fe836711cf50ed065a7180eed2f49360218d55541288aef7c02975b7871b37286699d739d407b
|
7
|
+
data.tar.gz: 2c8c02a86f16fa393a0168dadf80438892c26a2c224511eba68a1bb573d82bc968817136d0ccea31d87b8db47dd39ad7ac70f31362da15f2e896800bbeedd2a0
|
@@ -0,0 +1,13 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Provides asynchronous purging of ActiveStorage::Blob records via ActiveStorage::Blob#purge_later.
|
4
|
+
class ActiveStorage::PurgeJob < ActiveStorage::BaseJob
|
5
|
+
discard_on ActiveRecord::RecordNotFound
|
6
|
+
|
7
|
+
def perform(blob)
|
8
|
+
begin
|
9
|
+
blob&.purge
|
10
|
+
rescue
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module BetterRecord
|
4
|
+
class AttachmentValidation < ApplicationRecord
|
5
|
+
# == Constants ============================================================
|
6
|
+
|
7
|
+
# == Attributes ===========================================================
|
8
|
+
|
9
|
+
# == Extensions ===========================================================
|
10
|
+
|
11
|
+
# == Relationships ========================================================
|
12
|
+
belongs_to :attachment,
|
13
|
+
class_name: 'ActiveStorage::Attachment',
|
14
|
+
inverse_of: :validations
|
15
|
+
|
16
|
+
ActiveStorage::Attachment.has_many :validations,
|
17
|
+
class_name: 'BetterRecord::AttachmentValidation',
|
18
|
+
foreign_key: :attachment_id,
|
19
|
+
inverse_of: :attachment,
|
20
|
+
dependent: :destroy
|
21
|
+
# == Validations ==========================================================
|
22
|
+
|
23
|
+
# == Scopes ===============================================================
|
24
|
+
|
25
|
+
# == Callbacks ============================================================
|
26
|
+
|
27
|
+
# == Boolean Class Methods ================================================
|
28
|
+
|
29
|
+
# == Class Methods ========================================================
|
30
|
+
|
31
|
+
# == Boolean Methods ======================================================
|
32
|
+
|
33
|
+
# == Instance Methods =====================================================
|
34
|
+
|
35
|
+
end
|
36
|
+
end
|
@@ -16,12 +16,13 @@ module BetterRecord
|
|
16
16
|
min_image_size: nil,
|
17
17
|
max_image_size: 500.kilobytes,
|
18
18
|
shrink_large_image: false,
|
19
|
+
shrink_wait_time: 1.minute,
|
19
20
|
**opts
|
20
21
|
)
|
21
22
|
# == Constants ============================================================
|
22
23
|
|
23
24
|
# == Attributes ===========================================================
|
24
|
-
attribute :"
|
25
|
+
attribute :"shrinking_#{avatar_name}", :boolean, default: false
|
25
26
|
|
26
27
|
# == Extensions ===========================================================
|
27
28
|
|
@@ -30,25 +31,49 @@ module BetterRecord
|
|
30
31
|
has_one_attached avatar_name
|
31
32
|
|
32
33
|
# == Validations ==========================================================
|
33
|
-
validate avatar_name, image_validator
|
34
|
+
validate avatar_name, :"check_#{image_validator}"
|
34
35
|
|
35
36
|
# == Scopes ===============================================================
|
36
37
|
|
37
38
|
# == Callbacks ============================================================
|
38
|
-
|
39
|
+
after_commit :"check_#{image_validator}", if: :"#{avatar_name}_attached?", on: %i[ create update ]
|
39
40
|
|
40
41
|
# == Boolean Class Methods ================================================
|
41
42
|
|
42
43
|
# == Class Methods ========================================================
|
43
44
|
|
44
45
|
# == Boolean Methods ======================================================
|
46
|
+
define_method :"#{avatar_name}_attached?" do
|
47
|
+
__send__(avatar_name).attached?
|
48
|
+
end
|
49
|
+
|
50
|
+
define_method :"#{avatar_name}_validation_ran?" do |rld=false|
|
51
|
+
!!__send__(:"#{avatar_name}_validation_record", !!rld)&.ran
|
52
|
+
end
|
45
53
|
|
46
54
|
# == Instance Methods =====================================================
|
47
|
-
define_method :"attach_#{avatar_name}" do
|
48
|
-
__send__(avatar_name).attach(
|
55
|
+
define_method :"attach_#{avatar_name}" do |*args, **options|
|
56
|
+
__send__(avatar_name).attach(*args, **options)
|
49
57
|
__send__ image_validator
|
50
58
|
end
|
51
59
|
|
60
|
+
define_method :"create_#{avatar_name}_validation" do |ran=false|
|
61
|
+
begin
|
62
|
+
AttachmentValidation.create!(name: image_validator, attachment_id: __send__(avatar_name).id, ran: ran)
|
63
|
+
rescue
|
64
|
+
__send__(:"#{avatar_name}_validation_record").update(ran: true) if $!.is_a?(PG::UniqueViolation) && ran && !__send__(:"#{avatar_name}_validation_record").ran
|
65
|
+
end
|
66
|
+
__send__(:"#{avatar_name}_validation_record")
|
67
|
+
end
|
68
|
+
|
69
|
+
define_method :"#{avatar_name}_validation_record" do |rld=false|
|
70
|
+
(!rld && instance_variable_get(:"@#{avatar_name}_record")) ||
|
71
|
+
instance_variable_set(
|
72
|
+
:"@#{avatar_name}_record",
|
73
|
+
AttachmentValidation.find_by(attachment_id: __send__(avatar_name).id, name: image_validator)
|
74
|
+
)
|
75
|
+
end
|
76
|
+
|
52
77
|
define_method :valid_image_format do
|
53
78
|
unless __send__(avatar_name).blob.content_type.start_with? 'image/'
|
54
79
|
errors.add(avatar_name, 'is not an image file')
|
@@ -60,14 +85,19 @@ module BetterRecord
|
|
60
85
|
define_method :valid_image_size do
|
61
86
|
if max_image_size && __send__(avatar_name).blob.byte_size > max_image_size
|
62
87
|
if shrink_large_image.present?
|
63
|
-
|
64
|
-
|
88
|
+
puts "\nSHRINKING\n"
|
89
|
+
self.__send__ :"shrinking_#{avatar_name}=", true
|
90
|
+
(
|
91
|
+
shrink_wait_time ?
|
92
|
+
ResizeBlobImageJob.set(wait: shrink_wait_time) :
|
93
|
+
ResizeBlobImageJob
|
94
|
+
).perform_later(
|
65
95
|
model: self.class.to_s,
|
66
96
|
query: {id: self.id},
|
67
97
|
attachment: avatar_name.to_s,
|
68
|
-
backup_action: image_validator.to_s,
|
69
98
|
options: shrink_large_image
|
70
99
|
)
|
100
|
+
true
|
71
101
|
else
|
72
102
|
errors.add(avatar_name, "is too large, maximum #{ActiveSupport::NumberHelper.number_to_human_size(max_image_size)}")
|
73
103
|
return false
|
@@ -81,27 +111,33 @@ module BetterRecord
|
|
81
111
|
|
82
112
|
define_method :valid_image do
|
83
113
|
return true unless __send__(avatar_name).attached?
|
114
|
+
__send__(:"create_#{avatar_name}_validation", true)
|
84
115
|
|
85
116
|
if valid_image_format && valid_image_size
|
86
|
-
|
87
|
-
|
88
|
-
result = self.class.find_by(id: self.id).__send__(:"cache_current_#{avatar_name}")
|
89
|
-
puts "\n\nDONE COPYING AVATAR: #{result}\n\n"
|
90
|
-
result
|
117
|
+
self.__send__(:"shrinking_#{avatar_name}") ||
|
118
|
+
reloaded_record.__send__(:"cache_current_#{avatar_name}")
|
91
119
|
else
|
92
|
-
r =
|
93
|
-
|
120
|
+
r = reloaded_record.__send__(avatar_name)
|
121
|
+
begin
|
122
|
+
r.purge_later if r.attached?
|
123
|
+
rescue Exception
|
124
|
+
end
|
94
125
|
__send__(:"load_last_#{avatar_name}") if __send__(:"last_#{avatar_name}").attached?
|
95
126
|
false
|
96
127
|
end
|
97
128
|
end
|
98
129
|
|
130
|
+
define_method :"check_#{image_validator}" do |*args|
|
131
|
+
return true unless __send__(avatar_name).attached?
|
132
|
+
__send__(image_validator) unless __send__(:"#{avatar_name}_validation_ran?", true)
|
133
|
+
end
|
134
|
+
|
99
135
|
define_method :"cache_current_#{avatar_name}" do
|
100
|
-
__send__ :"copy_#{avatar_name}"
|
136
|
+
reloaded_record.__send__ :"copy_#{avatar_name}"
|
101
137
|
end
|
102
138
|
|
103
139
|
define_method :"load_last_#{avatar_name}" do
|
104
|
-
__send__ :"copy_#{avatar_name}", :"last_#{avatar_name}", avatar_name
|
140
|
+
reloaded_record.__send__ :"copy_#{avatar_name}", :"last_#{avatar_name}", avatar_name
|
105
141
|
end
|
106
142
|
|
107
143
|
define_method :"copy_#{avatar_name}" do |from = avatar_name, to = :"last_#{avatar_name}"|
|
@@ -109,23 +145,39 @@ module BetterRecord
|
|
109
145
|
from_attachment = __send__ from
|
110
146
|
to_attachment = __send__ to
|
111
147
|
|
112
|
-
|
148
|
+
if to_attachment.attached?
|
149
|
+
begin
|
150
|
+
atch = ActiveStorage::Attachment.find_by(to_attachment.id)
|
151
|
+
atch&.purge_later
|
152
|
+
rescue Exception
|
153
|
+
begin
|
154
|
+
ActiveStorage::Attachment.find_by(to_attachment.id).destroy
|
155
|
+
rescue Exception
|
156
|
+
end
|
157
|
+
end
|
158
|
+
end
|
113
159
|
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
160
|
+
if from_attachment.attached?
|
161
|
+
tmp = Tempfile.new
|
162
|
+
tmp.binmode
|
163
|
+
tmp.write(from_attachment.download)
|
164
|
+
tmp.flush
|
165
|
+
tmp.rewind
|
119
166
|
|
120
|
-
|
121
|
-
|
122
|
-
|
167
|
+
r = reloaded_record
|
168
|
+
from_attachment = r.__send__ from
|
169
|
+
to_attachment = r.__send__ to
|
123
170
|
|
124
|
-
|
125
|
-
|
171
|
+
to_attachment.attach(io: tmp, filename: from_attachment.filename, content_type: from_attachment.content_type)
|
172
|
+
tmp.close
|
173
|
+
end
|
126
174
|
true
|
127
175
|
end
|
128
176
|
|
177
|
+
define_method :reloaded_record do
|
178
|
+
self.class.find_by(id: self.id)
|
179
|
+
end
|
180
|
+
|
129
181
|
end
|
130
182
|
end
|
131
183
|
|
@@ -0,0 +1,15 @@
|
|
1
|
+
class CreateBetterRecordAttachmentValidations < ActiveRecord::Migration[5.2]
|
2
|
+
def change
|
3
|
+
create_table :better_record_attachment_validations do |t|
|
4
|
+
t.string :name, null: false
|
5
|
+
t.references :attachment, null: false
|
6
|
+
t.boolean :ran, null: false, default: false
|
7
|
+
|
8
|
+
t.index [ :attachment_id, :name ], name: "index_attachment_validations_uniqueness", unique: true
|
9
|
+
|
10
|
+
t.timestamps default: -> { 'NOW()' }
|
11
|
+
end
|
12
|
+
|
13
|
+
audit_table :better_record_attachment_validations
|
14
|
+
end
|
15
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: better_record
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.16.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Sampson Crowley
|
@@ -234,9 +234,11 @@ files:
|
|
234
234
|
- app/controllers/better_record/table_sizes_controller.rb
|
235
235
|
- app/helpers/better_record/application_helper.rb
|
236
236
|
- app/helpers/better_record/table_sizes_helper.rb
|
237
|
+
- app/jobs/active_storage/purge_job.rb
|
237
238
|
- app/jobs/better_record/application_job.rb
|
238
239
|
- app/jobs/better_record/resize_blob_image_job.rb
|
239
240
|
- app/mailers/better_record/application_mailer.rb
|
241
|
+
- app/models/better_record/attachment_validation.rb
|
240
242
|
- app/models/better_record/base.rb
|
241
243
|
- app/models/better_record/current.rb
|
242
244
|
- app/models/better_record/logged_action.rb
|
@@ -262,6 +264,7 @@ files:
|
|
262
264
|
- db/migrate/20180518042050_create_better_record_db_functions.rb
|
263
265
|
- db/migrate/20180518042060_create_better_record_custom_types.rb
|
264
266
|
- db/migrate/20180518042070_create_better_record_table_sizes.rb
|
267
|
+
- db/migrate/20181228204403_create_better_record_attachment_validations.rb
|
265
268
|
- db/postgres-audit-trigger.psql
|
266
269
|
- lib/better_record.rb
|
267
270
|
- lib/better_record/batches.rb
|