effective_assets 1.11.5 → 1.12.2
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 +4 -4
- data/app/jobs/effective/asset_replacer_job.rb +17 -0
- data/app/jobs/effective/snippet_replacer_job.rb +17 -0
- data/app/models/effective/asset_replacer.rb +157 -0
- data/app/models/effective/snippet_replacer.rb +67 -0
- data/lib/effective_assets/engine.rb +8 -4
- data/lib/effective_assets/version.rb +1 -1
- data/lib/tasks/replace_effective_assets.rake +5 -0
- data/lib/tasks/replace_effective_snippets.rake +5 -0
- metadata +8 -3
- data/app/models/effective/snippets/effective_asset.rb +0 -37
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8fc2ceb913a834e2d5a6c163e8aeccac4fd57f116239b59f1956c51c3a90053a
|
4
|
+
data.tar.gz: 6f24ae8f628864f2da0ab6ef66fb3cd9737c99fc3769c11c02e3aa9b7977a1bf
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4fc658672d3da2b57f573d3c3558d68028df4924e8982c8ac068d5dabddefaa5cd87942afeffbc95a2b7930310b23e8adac8eb21226cb29cba60b7fdafb008cf
|
7
|
+
data.tar.gz: b9690fd04a64c874d37d34453776ef065293461eb67b01ad1fa4019275151ab73c15973376425e36d370df898d21cea2d8e348fad7289524e0715bc520337d54
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module Effective
|
2
|
+
class AssetReplacerJob < ::ApplicationJob
|
3
|
+
|
4
|
+
queue_as :default
|
5
|
+
|
6
|
+
if defined?(Sidekiq)
|
7
|
+
# The retry setting works. But none of these waits seem to. Still getting exponential backoff.
|
8
|
+
sidekiq_options retry: 2, retry_in: 10, wait: 10
|
9
|
+
sidekiq_retry_in { |count, exception| 10 }
|
10
|
+
end
|
11
|
+
|
12
|
+
def perform(attachment, box)
|
13
|
+
Effective::AssetReplacer.new.replace_attachment!(attachment, box)
|
14
|
+
end
|
15
|
+
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module Effective
|
2
|
+
class SnippetReplacerJob < ::ApplicationJob
|
3
|
+
|
4
|
+
queue_as :default
|
5
|
+
|
6
|
+
if defined?(Sidekiq)
|
7
|
+
# The retry setting works. But none of these waits seem to. Still getting exponential backoff.
|
8
|
+
sidekiq_options retry: 2, retry_in: 10, wait: 10
|
9
|
+
sidekiq_retry_in { |count, exception| 10 }
|
10
|
+
end
|
11
|
+
|
12
|
+
def perform(region)
|
13
|
+
Effective::SnippetReplacer.new.replace_region!(region)
|
14
|
+
end
|
15
|
+
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,157 @@
|
|
1
|
+
# Looks at the Effective::Asset and Effective::Attachments and converts to ActiveStorage
|
2
|
+
#
|
3
|
+
# 1. Put in the has_attached_files to each model to be upgraded
|
4
|
+
# 2. Remove the acts_as_asset_box
|
5
|
+
|
6
|
+
require 'timeout'
|
7
|
+
require 'cgi'
|
8
|
+
|
9
|
+
module Effective
|
10
|
+
class AssetReplacer
|
11
|
+
include ActiveStorage::Blob::Analyzable
|
12
|
+
|
13
|
+
BATCH_SIZE = 500
|
14
|
+
TIMEOUT = 120
|
15
|
+
|
16
|
+
def replace!(skip_existing: false)
|
17
|
+
verify!
|
18
|
+
|
19
|
+
attachments = attachments_to_process().to_a
|
20
|
+
|
21
|
+
while(true)
|
22
|
+
wait_for_active_job!
|
23
|
+
|
24
|
+
puts "\nEnqueuing #{attachments.length} attachments with ids #{attachments.first.id} to #{attachments.last.id}"
|
25
|
+
|
26
|
+
attachments.each do |attachment|
|
27
|
+
asset = attachment.asset
|
28
|
+
attachable = attachment.attachable
|
29
|
+
next if asset.blank? || attachable.blank?
|
30
|
+
|
31
|
+
box = attachment.box.singularize
|
32
|
+
boxes = attachment.box
|
33
|
+
|
34
|
+
one = attachable.respond_to?(box) && attachable.send(box).kind_of?(ActiveStorage::Attached::One)
|
35
|
+
many = attachable.respond_to?(boxes) && attachable.send(boxes).kind_of?(ActiveStorage::Attached::Many)
|
36
|
+
box = (one ? box : boxes)
|
37
|
+
|
38
|
+
if skip_existing
|
39
|
+
existing = Array(attachable.send(box))
|
40
|
+
|
41
|
+
if existing.any? { |obj| obj.respond_to?(:filename) && obj.filename.to_s == asset.file_name }
|
42
|
+
puts("Skipping existing #{attachable.class.name} #{attachable.id} #{box} #{asset.file_name}.")
|
43
|
+
next
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
Effective::AssetReplacerJob.perform_later(attachment, box)
|
48
|
+
end
|
49
|
+
|
50
|
+
attachments = attachments_to_process().where.not(id: attachments.map(&:id))
|
51
|
+
break if attachments.to_a.blank?
|
52
|
+
|
53
|
+
GC.start
|
54
|
+
end
|
55
|
+
|
56
|
+
puts "\nAll Done. Have a great day."
|
57
|
+
true
|
58
|
+
end
|
59
|
+
|
60
|
+
# This is called on the background by the AssetReplacerJob
|
61
|
+
def replace_attachment!(attachment, box)
|
62
|
+
raise('expected an Effective::Attachment') unless attachment.kind_of?(Effective::Attachment)
|
63
|
+
puts("Processing attachment ##{attachment.id}")
|
64
|
+
|
65
|
+
asset = attachment.asset
|
66
|
+
attachable = attachment.attachable
|
67
|
+
|
68
|
+
attachable.replacing_asset = true if attachable.respond_to?(:replacing_asset=)
|
69
|
+
|
70
|
+
Timeout.timeout(TIMEOUT) do
|
71
|
+
attachable.send(box).attach(
|
72
|
+
io: URI.open(asset.url),
|
73
|
+
filename: CGI.unescape(asset.file_name.to_s),
|
74
|
+
content_type: asset.content_type.presence,
|
75
|
+
identify: (asset.content_type.blank?)
|
76
|
+
)
|
77
|
+
|
78
|
+
attachment.update_column(:replaced, true)
|
79
|
+
end
|
80
|
+
|
81
|
+
true
|
82
|
+
end
|
83
|
+
|
84
|
+
def verify!
|
85
|
+
raise('expected effective assets') unless defined?(Effective::Asset)
|
86
|
+
raise('expected active storage') unless defined?(ActiveStorage)
|
87
|
+
|
88
|
+
unless Effective::Attachment.new.respond_to?(:replaced?)
|
89
|
+
raise('please add a replaced boolean to Effective::Attachment. add_column :attachments, :replaced, :boolean')
|
90
|
+
end
|
91
|
+
|
92
|
+
(Effective::Attachment.all.pluck(:attachable_type, :box).uniq).each do |name, boxes|
|
93
|
+
next if name.blank? || boxes.blank?
|
94
|
+
|
95
|
+
box = boxes.singularize
|
96
|
+
|
97
|
+
klass = name.safe_constantize
|
98
|
+
raise("invalid class #{klass}") unless klass.present?
|
99
|
+
|
100
|
+
instance = klass.new
|
101
|
+
|
102
|
+
if instance.respond_to?(:effective_assets)
|
103
|
+
raise("please remove acts_as_asset_box() from #{klass.name}")
|
104
|
+
end
|
105
|
+
|
106
|
+
unless instance.respond_to?(box) || instance.respond_to?(boxes)
|
107
|
+
raise("expected #{klass.name} to has_one_attached :#{box} or has_many_attached :#{boxes}")
|
108
|
+
end
|
109
|
+
|
110
|
+
one = instance.respond_to?(box) && instance.send(box).kind_of?(ActiveStorage::Attached::One)
|
111
|
+
many = instance.respond_to?(boxes) && instance.send(boxes).kind_of?(ActiveStorage::Attached::Many)
|
112
|
+
|
113
|
+
unless one.present? || many.present?
|
114
|
+
raise("expected #{klass.name} to has_one_attached :#{box} or has_many_attached :#{boxes}")
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
puts 'All attachment classes verified.'
|
119
|
+
|
120
|
+
true
|
121
|
+
end
|
122
|
+
|
123
|
+
def reset!
|
124
|
+
Effective::Attachment.update_all(replaced: false)
|
125
|
+
end
|
126
|
+
|
127
|
+
private
|
128
|
+
|
129
|
+
def wait_for_active_job!
|
130
|
+
while(true)
|
131
|
+
if(jobs = enqueued_jobs_count) > (BATCH_SIZE / 10)
|
132
|
+
print '.'; sleep(3)
|
133
|
+
else
|
134
|
+
break
|
135
|
+
end
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
# The last BATCH_SIZE attachments
|
140
|
+
def attachments_to_process
|
141
|
+
Effective::Attachment.all
|
142
|
+
.includes(:asset)
|
143
|
+
.where(replaced: [nil, false])
|
144
|
+
.reorder(id: :desc)
|
145
|
+
.limit(BATCH_SIZE)
|
146
|
+
end
|
147
|
+
|
148
|
+
def enqueued_jobs_count
|
149
|
+
if Rails.application.config.active_job.queue_adapter == :sidekiq
|
150
|
+
Sidekiq::Stats.new.enqueued.to_i
|
151
|
+
else
|
152
|
+
ActiveJob::Base.queue_adapter.enqueued_jobs.count
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
end
|
157
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
# Replaces the [snippet_x] in all effective regions with static content
|
2
|
+
|
3
|
+
module Effective
|
4
|
+
class SnippetReplacer
|
5
|
+
include ActiveStorage::Blob::Analyzable
|
6
|
+
include ActionView::Helpers::UrlHelper
|
7
|
+
include ActionView::Helpers::AssetTagHelper
|
8
|
+
|
9
|
+
def replace!
|
10
|
+
raise('expected effective regions') unless defined?(Effective::Region)
|
11
|
+
raise('expected effective assets') unless defined?(Effective::Asset)
|
12
|
+
raise('expected active storage') unless defined?(ActiveStorage)
|
13
|
+
|
14
|
+
Effective::Region.with_snippets.find_each do |region|
|
15
|
+
Effective::SnippetReplacerJob.perform_later(region)
|
16
|
+
end
|
17
|
+
|
18
|
+
puts 'All Done. Background jobs are running. Have a great day.'
|
19
|
+
true
|
20
|
+
end
|
21
|
+
|
22
|
+
def replace_region!(region)
|
23
|
+
region.snippet_objects.each do |snippet|
|
24
|
+
print('.')
|
25
|
+
|
26
|
+
begin
|
27
|
+
case snippet.class.name
|
28
|
+
when 'Effective::Snippets::EffectiveAsset'
|
29
|
+
replace_effective_asset(region, snippet)
|
30
|
+
else
|
31
|
+
raise("unsupported snippet: #{snippet.class.name}")
|
32
|
+
end
|
33
|
+
rescue => e
|
34
|
+
puts "\nError: #{e}\n"
|
35
|
+
remove_snippet(region, snippet)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
region.save!
|
40
|
+
end
|
41
|
+
|
42
|
+
def replace_effective_asset(region, snippet)
|
43
|
+
asset = snippet.asset
|
44
|
+
raise("Effective:Asset id=#{snippet.asset_id || 'none'} does not exist") unless asset.present?
|
45
|
+
|
46
|
+
blob = ActiveStorage::Blob.create_and_upload!(io: URI.open(asset.url), filename: asset.file_name)
|
47
|
+
url = Rails.application.routes.url_helpers.rails_blob_url(blob, only_path: true)
|
48
|
+
|
49
|
+
content = if asset.image?
|
50
|
+
image_tag(url, class: snippet.html_class, alt: snippet.link_title)
|
51
|
+
else
|
52
|
+
link_to(snippet.link_title, url, class: snippet.html_class, title: snippet.link_title)
|
53
|
+
end
|
54
|
+
|
55
|
+
region.content.sub!("[#{snippet.id}]", content.to_s)
|
56
|
+
region.snippets.delete(snippet.id)
|
57
|
+
|
58
|
+
true
|
59
|
+
end
|
60
|
+
|
61
|
+
def remove_snippet(region, snippet)
|
62
|
+
region.content.sub!("[#{snippet.id}]", '')
|
63
|
+
region.snippets.delete(snippet.id)
|
64
|
+
end
|
65
|
+
|
66
|
+
end
|
67
|
+
end
|
@@ -8,14 +8,18 @@ module EffectiveAssets
|
|
8
8
|
|
9
9
|
# Include acts_as_addressable concern and allow any ActiveRecord object to call it
|
10
10
|
initializer 'effective_assets.active_record' do |app|
|
11
|
-
|
12
|
-
|
11
|
+
app.config.to_prepare do
|
12
|
+
ActiveSupport.on_load :active_record do
|
13
|
+
ActiveRecord::Base.extend(ActsAsAssetBox::ActiveRecord)
|
14
|
+
end
|
13
15
|
end
|
14
16
|
end
|
15
17
|
|
16
18
|
initializer 'effective_assets.action_view' do |app|
|
17
|
-
|
18
|
-
|
19
|
+
app.config.to_prepare do
|
20
|
+
ActiveSupport.on_load :action_view do
|
21
|
+
ActionView::Helpers::FormBuilder.send(:include, AssetBoxFormInput)
|
22
|
+
end
|
19
23
|
end
|
20
24
|
end
|
21
25
|
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: effective_assets
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.12.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Code and Effect
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2022-04-06 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|
@@ -165,14 +165,17 @@ files:
|
|
165
165
|
- app/controllers/effective/s3_uploads_controller.rb
|
166
166
|
- app/helpers/effective_assets_helper.rb
|
167
167
|
- app/helpers/effective_assets_s3_helper.rb
|
168
|
+
- app/jobs/effective/asset_replacer_job.rb
|
168
169
|
- app/jobs/effective/process_with_active_job.rb
|
169
170
|
- app/jobs/effective/process_with_sucker_punch_job.rb
|
171
|
+
- app/jobs/effective/snippet_replacer_job.rb
|
170
172
|
- app/models/concerns/acts_as_asset_box.rb
|
171
173
|
- app/models/effective/access_denied.rb
|
172
174
|
- app/models/effective/asset.rb
|
175
|
+
- app/models/effective/asset_replacer.rb
|
173
176
|
- app/models/effective/attachment.rb
|
174
177
|
- app/models/effective/iframe_upload.rb
|
175
|
-
- app/models/effective/
|
178
|
+
- app/models/effective/snippet_replacer.rb
|
176
179
|
- app/uploaders/effective_assets_uploader.rb
|
177
180
|
- app/uploaders/test_asset_uploader.rb
|
178
181
|
- app/views/active_admin/effective_assets/_edit.html.haml
|
@@ -201,6 +204,8 @@ files:
|
|
201
204
|
- lib/inputs/asset_box_input.rb
|
202
205
|
- lib/inputs/asset_box_simple_form_input.rb
|
203
206
|
- lib/tasks/effective_assets_tasks.rake
|
207
|
+
- lib/tasks/replace_effective_assets.rake
|
208
|
+
- lib/tasks/replace_effective_snippets.rake
|
204
209
|
- lib/validators/asset_box_length_validator.rb
|
205
210
|
- lib/validators/asset_box_presence_validator.rb
|
206
211
|
homepage: https://github.com/code-and-effect/effective_assets
|
@@ -1,37 +0,0 @@
|
|
1
|
-
if defined?(EffectiveRegions)
|
2
|
-
module Effective
|
3
|
-
module Snippets
|
4
|
-
class EffectiveAsset < Snippet
|
5
|
-
# attr_accessor :asset_id #, Integer
|
6
|
-
# attr_accessor :html_class #, String
|
7
|
-
# attr_accessor :link_title #, String
|
8
|
-
# attr_accessor :private_url # , Boolean
|
9
|
-
|
10
|
-
def snippet_attributes
|
11
|
-
super + [:asset_id, :html_class, :link_title, :private_url]
|
12
|
-
end
|
13
|
-
|
14
|
-
def asset
|
15
|
-
@asset ||= (Effective::Asset.where(:id => asset_id).first if asset_id)
|
16
|
-
end
|
17
|
-
|
18
|
-
def snippet_tag
|
19
|
-
:span
|
20
|
-
end
|
21
|
-
|
22
|
-
def private_url
|
23
|
-
super || aws_private?
|
24
|
-
end
|
25
|
-
|
26
|
-
def is_private?
|
27
|
-
[true, 'true', '1'].include?(private_url)
|
28
|
-
end
|
29
|
-
|
30
|
-
def aws_private?
|
31
|
-
(asset.try(:aws_acl) == EffectiveAssets::AWS_PRIVATE)
|
32
|
-
end
|
33
|
-
|
34
|
-
end
|
35
|
-
end
|
36
|
-
end
|
37
|
-
end
|