effective_developer 0.6.4 → 0.6.5

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: 3d495b7c0e191545d03edac8297a4e6d70b0e73c60e3e750a7746a43a9c45ae0
4
- data.tar.gz: fda29335818a87f2e76bd21c4f8018aab29833082682ca931339a127d7a9d1d0
3
+ metadata.gz: d5ec0b8ebeb89650bcd3faa9d72db0a63e59d412da44774ddf243cb41e2e27f9
4
+ data.tar.gz: 030ee9a657eecd09ecbe4b35340c7a50d05128b7320ad8b098449088bd9b55d9
5
5
  SHA512:
6
- metadata.gz: 4bbed134e5bc6f0b78231501cd866a581a878dd4b5734ca74b480bfc49bc014c25a5e2a23074a62ccdc4ac90d40220ed6a7f5fb42a8c68c44979fd909d427635
7
- data.tar.gz: b97abb74e30855a39100c9ca66785e89148bfda8e1cc427170b67767007078a5818e194adf34541806d6c4809a3b45bf1bfba97305bff663c4643c21c319d347
6
+ metadata.gz: 710dc72a3a8e31c031e7c357429e721ae4b550facca68fcf70054e6bcd1b3f6275e12619e4bbc5174e49077f6803290b6e5e2fe5c955a9d028630ff5815210ba
7
+ data.tar.gz: d57c9a3f9697100ea078dbd6de9be128935349ec98380da04336c0a0d24edd6699fa4286b14464b834ed85fb813f3da7c7f3a16e129506be80ee2bbe6c95b46e
data/MIT-LICENSE CHANGED
@@ -1,4 +1,4 @@
1
- Copyright 2018 Code and Effect Inc.
1
+ Copyright 2021 Code and Effect Inc.
2
2
 
3
3
  Permission is hereby granted, free of charge, to any person obtaining
4
4
  a copy of this software and associated documentation files (the
@@ -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,143 @@
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
+
8
+ module Effective
9
+ class AssetReplacer
10
+ include ActiveStorage::Blob::Analyzable
11
+
12
+ BATCH_SIZE = 500
13
+ TIMEOUT = 120
14
+
15
+ def replace!(force: false)
16
+ verify!
17
+
18
+ attachments_to_process().find_in_batches(batch_size: BATCH_SIZE).each do |attachments|
19
+ wait_for_active_job!
20
+
21
+ puts "\nEnqueuing #{attachments.length} attachments with ids #{attachments.first.id} to #{attachments.last.id}"
22
+
23
+ attachments.each do |attachment|
24
+ asset = attachment.asset
25
+ attachable = attachment.attachable
26
+ next if asset.blank? || attachable.blank?
27
+
28
+ box = attachment.box.singularize
29
+ boxes = attachment.box
30
+
31
+ one = attachable.respond_to?(box) && attachable.send(box).kind_of?(ActiveStorage::Attached::One)
32
+ many = attachable.respond_to?(boxes) && attachable.send(boxes).kind_of?(ActiveStorage::Attached::Many)
33
+ box = (one ? box : boxes)
34
+
35
+ unless force
36
+ existing = Array(attachable.send(box))
37
+
38
+ if existing.any? { |obj| obj.respond_to?(:filename) && obj.filename.to_s == asset.file_name }
39
+ puts("Skipping: #{attachable.class.name} #{attachable.id} #{box} #{asset.file_name}. Already exists."); next
40
+ end
41
+ end
42
+
43
+ Effective::AssetReplacerJob.perform_later(attachment, box)
44
+ end
45
+ end
46
+
47
+ puts "\nAll Done. Have a great day."
48
+ true
49
+ end
50
+
51
+ # This is called on the background by the AssetReplacerJob
52
+ def replace_attachment!(attachment, box)
53
+ raise('expected an Effective::Attachment') unless attachment.kind_of?(Effective::Attachment)
54
+ puts("Processing attachment ##{attachment.id}")
55
+
56
+ asset = attachment.asset
57
+ attachable = attachment.attachable
58
+
59
+ attachable.upgrading = true if attachable.respond_to?(:upgrading=)
60
+
61
+ Timeout.timeout(TIMEOUT) do
62
+ attachable.send(box).attach(
63
+ io: URI.open(asset.url),
64
+ filename: asset.file_name,
65
+ content_type: asset.content_type.presence,
66
+ identify: (asset.content_type.blank?)
67
+ )
68
+
69
+ attachment.update_column(:replaced, true)
70
+ end
71
+
72
+ true
73
+ end
74
+
75
+ def verify!
76
+ raise('expected effective assets') unless defined?(Effective::Asset)
77
+ raise('expected active storage') unless defined?(ActiveStorage)
78
+
79
+ unless Effective::Attachment.new.respond_to?(:replaced?)
80
+ raise('please add a replaced boolean to Effective::Attachment. add_column :attachments, :replaced, :boolean')
81
+ end
82
+
83
+ (Effective::Attachment.all.pluck(:attachable_type, :box).uniq).each do |name, boxes|
84
+ next if name.blank? || boxes.blank?
85
+
86
+ box = boxes.singularize
87
+
88
+ klass = name.safe_constantize
89
+ raise("invalid class #{klass}") unless klass.present?
90
+
91
+ instance = klass.new
92
+
93
+ if instance.respond_to?(:effective_assets)
94
+ raise("please remove acts_as_asset_box() from #{klass.name}")
95
+ end
96
+
97
+ unless instance.respond_to?(box) || instance.respond_to?(boxes)
98
+ raise("expected #{klass.name} to has_one_attached :#{box} or has_many_attached :#{boxes}")
99
+ end
100
+
101
+ one = instance.respond_to?(box) && instance.send(box).kind_of?(ActiveStorage::Attached::One)
102
+ many = instance.respond_to?(boxes) && instance.send(boxes).kind_of?(ActiveStorage::Attached::Many)
103
+
104
+ unless one.present? || many.present?
105
+ raise("expected #{klass.name} to has_one_attached :#{box} or has_many_attached :#{boxes}")
106
+ end
107
+ end
108
+
109
+ puts 'All attachment classes verified.'
110
+
111
+ true
112
+ end
113
+
114
+ def reset!
115
+ Effective::Attachment.update_all(replaced: false)
116
+ end
117
+
118
+ private
119
+
120
+ def wait_for_active_job!
121
+ while(true)
122
+ if(jobs = enqueued_jobs_count) > (BATCH_SIZE / 10)
123
+ print '.'; sleep(2)
124
+ else
125
+ break
126
+ end
127
+ end
128
+ end
129
+
130
+ def attachments_to_process
131
+ Effective::Attachment.all.where(replaced: [nil, false]).order(:id).where('id < ?', 10000)
132
+ end
133
+
134
+ def enqueued_jobs_count
135
+ if Rails.application.config.active_job.queue_adapter == :sidekiq
136
+ Sidekiq::Stats.new.enqueued.to_i
137
+ else
138
+ ActiveJob::Base.queue_adapter.enqueued_jobs.count
139
+ end
140
+ end
141
+
142
+ end
143
+ end
@@ -0,0 +1,66 @@
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
+ region.snippet_objects.each do |snippet|
16
+ print('.')
17
+
18
+ begin
19
+ case snippet.class.name
20
+ when 'Effective::Snippets::EffectiveAsset'
21
+ replace_effective_asset(region, snippet)
22
+ else
23
+ raise("unsupported snippet: #{snippet.class.name}")
24
+ end
25
+ rescue => e
26
+ puts "\nError: #{e}\n"
27
+ remove_snippet(region, snippet)
28
+ end
29
+ end
30
+
31
+ region.save!
32
+ end
33
+
34
+ puts 'All Done. Have a great day.'
35
+ true
36
+ end
37
+
38
+ private
39
+
40
+ def replace_effective_asset(region, snippet)
41
+ asset = snippet.asset
42
+ raise("Effective:Asset id=#{snippet.asset_id || 'none'} does not exist") unless asset.present?
43
+
44
+ blob = ActiveStorage::Blob.create_and_upload!(io: URI.open(asset.url), filename: asset.file_name)
45
+ url = Rails.application.routes.url_helpers.rails_blob_url(blob, only_path: true)
46
+
47
+ content = if asset.image?
48
+ image_tag(url, class: snippet.html_class, alt: snippet.link_title)
49
+ else
50
+ link_to(snippet.link_title, url, class: snippet.html_class, title: snippet.link_title)
51
+ end
52
+
53
+ region.content.sub!("[#{snippet.id}]", content.to_s)
54
+ region.snippets.delete(snippet.id)
55
+
56
+ true
57
+ end
58
+
59
+ def remove_snippet(region, snippet)
60
+ region.content.sub!("[#{snippet.id}]", '')
61
+ region.snippets.delete(snippet.id)
62
+ end
63
+
64
+
65
+ end
66
+ end
@@ -2,6 +2,9 @@ module EffectiveDeveloper
2
2
  class Engine < ::Rails::Engine
3
3
  engine_name 'effective_developer'
4
4
 
5
+ config.autoload_paths += Dir["#{config.root}/models/jobs/"]
6
+ config.eager_load_paths += Dir["#{config.root}/models/jobs/"]
7
+
5
8
  # Set up our default configuration options.
6
9
  initializer 'effective_developer.defaults', before: :load_config_initializers do |app|
7
10
  # Set up our defaults, as per our initializer template
@@ -1,3 +1,3 @@
1
1
  module EffectiveDeveloper
2
- VERSION = '0.6.4'.freeze
2
+ VERSION = '0.6.5'.freeze
3
3
  end
@@ -0,0 +1,5 @@
1
+ # bundle exec rake replace_assets
2
+ desc 'Replaces effective_assets with ActiveStorage'
3
+ task :replace_assets => :environment do
4
+ Effective::AssetReplacer.new.replace!
5
+ end
@@ -0,0 +1,5 @@
1
+ # bundle exec rake replace_snippets
2
+ desc 'Replaces effective_assets snippets with ActiveStorage uploads'
3
+ task :replace_snippets => :environment do
4
+ Effective::SnippetReplacer.new.replace!
5
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: effective_developer
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.4
4
+ version: 0.6.5
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: 2021-06-03 00:00:00.000000000 Z
11
+ date: 2021-07-05 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -48,12 +48,15 @@ files:
48
48
  - MIT-LICENSE
49
49
  - README.md
50
50
  - Rakefile
51
+ - app/jobs/effective/asset_replacer_job.rb
51
52
  - app/models/effective/annotator.rb
53
+ - app/models/effective/asset_replacer.rb
52
54
  - app/models/effective/code_writer.rb
53
55
  - app/models/effective/csv_importer.rb
54
56
  - app/models/effective/form_upgrader.rb
55
57
  - app/models/effective/live_generator.rb
56
58
  - app/models/effective/profiler.rb
59
+ - app/models/effective/snippet_replacer.rb
57
60
  - config/effective_developer.rb
58
61
  - lib/effective_developer.rb
59
62
  - lib/effective_developer/engine.rb
@@ -101,6 +104,8 @@ files:
101
104
  - lib/tasks/effective_csv_importer.rake
102
105
  - lib/tasks/pg_pull.rake
103
106
  - lib/tasks/rename_class.rake
107
+ - lib/tasks/replace_assets.rake
108
+ - lib/tasks/replace_snippets.rake
104
109
  - lib/tasks/reset_pk_sequence.rake
105
110
  - lib/tasks/upgrade_forms.rake
106
111
  - lib/tasks/validate.rake