better_record 0.15.2 → 0.16.0

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 38d1f355a28bcc6fa75e43137e4f6d2096c78b85de3420733cf201826424e22d
4
- data.tar.gz: d5da519726817d407cc67a027041dc0c258daf715f6c8675de934cda2c3b626b
3
+ metadata.gz: 669acb9b867dcb30b92fbe9d4d147f97c60862aedebd1a9a5f9319577f262b17
4
+ data.tar.gz: fea7a77007c6279d2c0ad4b9845f22579b9ff608e54e49f306d36da4d68198f4
5
5
  SHA512:
6
- metadata.gz: 2cdb3aeac811064a91c3450942a5e5f0776e539aba2300a14c2ec7f2883caaf985d745e44a0dfaa5761ed794a0ba37322e2583c5d014435c5e5364852799c223
7
- data.tar.gz: 7e965a6f43b3fb45b47ab026d682bf00294ec8b417077183189d85c39f965d247eb6a83d90e6d3a0e59c2194e4aa938a1c1d7a748262962a64fef211be494892
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 :"new_#{avatar_name}?", :boolean
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
- after_save :"cache_current_#{avatar_name}", if: :"new_#{avatar_name}?"
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 |file, **options|
48
- __send__(avatar_name).attach(file, **options)
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
- @copy_later = true
64
- ResizeBlobImageJob.perform_later(
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
- return true if @copy_later
87
- puts "\n\nCOPYING AVATAR\n\n"
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 = self.find_by(id: self.id).__send__(avatar_name)
93
- r.purge if r.attached?
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
- purge(to_attachment) if to_attachment.attached?
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
- tmp = Tempfile.new
115
- tmp.binmode
116
- tmp.write(from_attachment.download)
117
- tmp.flush
118
- tmp.rewind
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
- r = self.class.find_by(id: self.id)
121
- from_attachment = r.__send__ from
122
- to_attachment = r.__send__ to
167
+ r = reloaded_record
168
+ from_attachment = r.__send__ from
169
+ to_attachment = r.__send__ to
123
170
 
124
- to_attachment.attach(io: tmp, filename: from_attachment.filename, content_type: from_attachment.content_type)
125
- tmp.close
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
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module BetterRecord
4
- VERSION = '0.15.2'
4
+ VERSION = '0.16.0'
5
5
  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.15.2
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