Skip to content

Commit 6844e58

Browse files
committed
Add upgrader for active storage
1 parent 206e2b6 commit 6844e58

19 files changed

+279
-28
lines changed

Diff for: alchemy_cms.gemspec

+2
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,8 @@ Gem::Specification.new do |gem|
3838
gem.add_runtime_dependency "awesome_nested_set", ["~> 3.1"]
3939
gem.add_runtime_dependency "cancancan", [">= 2.1", "< 4.0"]
4040
gem.add_runtime_dependency "coffee-rails", [">= 4.0", "< 6.0"]
41+
gem.add_runtime_dependency "dragonfly", ["~> 1.4"]
42+
gem.add_runtime_dependency "dragonfly_svg", ["~> 0.0.4"]
4143
gem.add_runtime_dependency "gutentag", ["~> 2.2", ">= 2.2.1"]
4244
gem.add_runtime_dependency "handlebars_assets", ["~> 0.23"]
4345
gem.add_runtime_dependency "image_processing", [">= 1.2"]

Diff for: app/models/alchemy/attachment.rb

+13
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,19 @@ class Attachment < BaseRecord
2424
include Alchemy::Taggable
2525
include Alchemy::TouchElements
2626

27+
# Legacy Dragonfly file attachments
28+
extend Dragonfly::Model
29+
dragonfly_accessor :legacy_file, app: :alchemy_attachments
30+
DEPRECATED_COLUMNS = %i[
31+
legacy_file
32+
legacy_file_name
33+
legacy_file_size
34+
legacy_file_uid
35+
].each do |column|
36+
deprecate column, deprecator: Alchemy::Deprecation
37+
deprecate :"#{column}=", deprecator: Alchemy::Deprecation
38+
end
39+
2740
# Use ActiveStorage file attachments
2841
has_one_attached :file, service: :alchemy_cms
2942

Diff for: app/models/alchemy/picture.rb

+16
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,22 @@ def self.preprocessor_class=(klass)
8080
@_preprocessor_class = klass
8181
end
8282

83+
# Legacy Dragonfly image attachments
84+
extend Dragonfly::Model
85+
dragonfly_accessor :legacy_image_file, app: :alchemy_pictures
86+
DEPRECATED_COLUMNS = %i[
87+
legacy_image_file
88+
legacy_image_file_format
89+
legacy_image_file_height
90+
legacy_image_file_name
91+
legacy_image_file_size
92+
legacy_image_file_uid
93+
legacy_image_file_width
94+
].each do |column|
95+
deprecate column, deprecator: Alchemy::Deprecation
96+
deprecate :"#{column}=", deprecator: Alchemy::Deprecation
97+
end
98+
8399
# Use ActiveStorage image processing
84100
has_one_attached :image_file, service: :alchemy_cms
85101

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
class RenameAlchemyAttachmentFile < ActiveRecord::Migration[7.0]
2+
COLUMNS = %i[
3+
file_name
4+
file_size
5+
file_uid
6+
]
7+
8+
def change
9+
COLUMNS.each do |column|
10+
rename_column :alchemy_attachments, column, :"legacy_#{column}"
11+
end
12+
end
13+
end
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
class RenameAlchemyPictureImageFile < ActiveRecord::Migration[7.0]
2+
COLUMNS = %i[
3+
image_file_format
4+
image_file_height
5+
image_file_name
6+
image_file_size
7+
image_file_uid
8+
image_file_width
9+
]
10+
11+
def change
12+
COLUMNS.each do |column|
13+
rename_column :alchemy_pictures, column, :"legacy_#{column}"
14+
end
15+
end
16+
end

Diff for: lib/alchemy/test_support/factories/attachment_factory.rb

-1
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,5 @@
2020
end
2121

2222
name { "image" }
23-
file_name { "image.png" }
2423
end
2524
end

Diff for: lib/alchemy/upgrader/seven_point_three.rb

+128
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
# frozen_string_literal: true
2+
3+
require "alchemy/shell"
4+
require "benchmark"
5+
require "active_storage/service/disk_service"
6+
7+
module Alchemy
8+
class Upgrader::SevenPointThree < Upgrader
9+
extend Alchemy::Shell
10+
DEFAULT_CONTENT_TYPE = "application/octet-stream"
11+
DISK_SERVICE = ActiveStorage::Service::DiskService
12+
SERVICE_NAME = :alchemy_cms
13+
14+
# Prevents (down)loading the original file
15+
METADATA = {
16+
identified: true, # Skip identifying file type
17+
analyzed: true, # Skip analyze job
18+
composed: true # Skip checksum check
19+
}
20+
21+
class << self
22+
def migrate_pictures_to_active_storage
23+
pictures_without_as_attachment = Alchemy::Picture.where.missing(:image_file_attachment)
24+
count = pictures_without_as_attachment.count
25+
if count > 0
26+
log "Migrating #{count} Dragonfly image file(s) to ActiveStorage."
27+
realtime = Benchmark.realtime do
28+
pictures_without_as_attachment.find_each do |picture|
29+
Alchemy::Deprecation.silence do
30+
uid = picture.legacy_image_file_uid
31+
key = key_for_uid(uid)
32+
content_type = Mime::Type.lookup_by_extension(picture.legacy_image_file_format) || DEFAULT_CONTENT_TYPE
33+
Alchemy::Picture.transaction do
34+
blob = ActiveStorage::Blob.create!(
35+
key: key,
36+
filename: picture.legacy_image_file_name,
37+
byte_size: picture.legacy_image_file_size,
38+
content_type: content_type,
39+
metadata: METADATA.merge(
40+
width: picture.legacy_image_file_width,
41+
height: picture.legacy_image_file_height
42+
),
43+
service_name: SERVICE_NAME
44+
)
45+
picture.create_image_file_attachment!(
46+
name: :image_file,
47+
record: picture,
48+
blob: blob
49+
)
50+
end
51+
move_file(Rails.root.join("uploads/pictures", uid), key)
52+
end
53+
print "."
54+
end
55+
end
56+
puts "\nDone in #{realtime.round(2)}s!"
57+
else
58+
log "No Dragonfly image files for migration found.", :skip
59+
end
60+
end
61+
62+
def migrate_attachments_to_active_storage
63+
attachments_without_as_attachment = Alchemy::Attachment.where.missing(:file_attachment)
64+
count = attachments_without_as_attachment.count
65+
if count > 0
66+
log "Migrating #{count} Dragonfly attachment file(s) to ActiveStorage."
67+
realtime = Benchmark.realtime do
68+
attachments_without_as_attachment.find_each do |attachment|
69+
Alchemy::Deprecation.silence do
70+
uid = attachment.legacy_file_uid
71+
key = key_for_uid(uid)
72+
Alchemy::Attachment.transaction do
73+
blob = ActiveStorage::Blob.create!(
74+
key: key,
75+
filename: attachment.legacy_file_name,
76+
byte_size: attachment.legacy_file_size,
77+
content_type: attachment.file_mime_type.presence || DEFAULT_CONTENT_TYPE,
78+
metadata: METADATA,
79+
service_name: SERVICE_NAME
80+
)
81+
attachment.create_file_attachment!(
82+
record: attachment,
83+
name: :file,
84+
blob: blob
85+
)
86+
end
87+
move_file(Rails.root.join("uploads/attachments", uid), key)
88+
end
89+
print "."
90+
end
91+
end
92+
puts "\nDone in #{realtime.round(2)}s!"
93+
else
94+
log "No Dragonfly attachment files for migration found.", :skip
95+
end
96+
end
97+
98+
private
99+
100+
# ActiveStorage::Service::DiskService stores files in a folder structure
101+
# based on the first two characters of the file uid.
102+
def key_for_uid(uid)
103+
case service
104+
when DISK_SERVICE
105+
uid.split("/").last
106+
else
107+
uid
108+
end
109+
end
110+
111+
# ActiveStorage::Service::DiskService stores files in a folder structure
112+
# based on the first two characters of the file uid.
113+
def move_file(uid, key)
114+
case service
115+
when DISK_SERVICE
116+
if File.exist?(uid)
117+
service.send(:make_path_for, key)
118+
FileUtils.mv uid, service.send(:path_for, key)
119+
end
120+
end
121+
end
122+
123+
def service
124+
ActiveStorage::Blob.services.fetch(SERVICE_NAME)
125+
end
126+
end
127+
end
128+
end

Diff for: lib/alchemy_cms.rb

+2
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@
99
require "active_model_serializers"
1010
require "awesome_nested_set"
1111
require "cancan"
12+
require "dragonfly"
13+
require "dragonfly_svg"
1214
require "gutentag"
1315
require "handlebars_assets"
1416
require "importmap-rails"

Diff for: lib/generators/alchemy/install/install_generator.rb

+9
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,15 @@ def install_assets
6767
copy_file "all.js", app_vendor_assets_path.join("javascripts", "alchemy", "admin", "all.js")
6868
end
6969

70+
def set_active_storage_service
71+
insert_into_file app_config_path.join("storage.yml"), <<-YAML.strip_heredoc
72+
73+
alchemy_cms:
74+
service: Disk
75+
root: <%= Rails.root.join("storage") %>
76+
YAML
77+
end
78+
7079
def copy_demo_views
7180
return if options[:skip_demo_files]
7281

Diff for: lib/tasks/alchemy/upgrade.rake

+27-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@ namespace :alchemy do
77
desc "Upgrades your app to AlchemyCMS v#{Alchemy::VERSION}."
88
task upgrade: [
99
"alchemy:upgrade:prepare",
10-
"alchemy:upgrade:7.0:run"
10+
"alchemy:upgrade:7.0:run",
11+
"alchemy:upgrade:7.3:run"
1112
] do
1213
Alchemy::Upgrader.display_todos
1314
end
@@ -49,5 +50,30 @@ namespace :alchemy do
4950
Alchemy::Upgrader::SevenPointZero.remove_admin_entrypoint
5051
end
5152
end
53+
54+
desc "Upgrade Alchemy to v7.3"
55+
task "7.3" => [
56+
"alchemy:upgrade:prepare",
57+
"alchemy:upgrade:7.3:run"
58+
] do
59+
Alchemy::Upgrader.display_todos
60+
end
61+
62+
namespace "7.3" do
63+
task "run" => [
64+
"alchemy:upgrade:7.3:migrate_pictures_to_active_storage",
65+
"alchemy:upgrade:7.3:migrate_attachments_to_active_storage"
66+
]
67+
68+
desc "Migrate pictures to active_storage"
69+
task migrate_pictures_to_active_storage: [:environment] do
70+
Alchemy::Upgrader::SevenPointThree.migrate_pictures_to_active_storage
71+
end
72+
73+
desc "Migrate attachments to active_storage"
74+
task migrate_attachments_to_active_storage: [:environment] do
75+
Alchemy::Upgrader::SevenPointThree.migrate_attachments_to_active_storage
76+
end
77+
end
5278
end
5379
end

Diff for: spec/dummy/config/storage.yml

+4
Original file line numberDiff line numberDiff line change
@@ -32,3 +32,7 @@ local:
3232
# service: Mirror
3333
# primary: local
3434
# mirrors: [ amazon, google, microsoft ]
35+
36+
alchemy_cms:
37+
service: Disk
38+
root: <%= Rails.root.join("storage") %>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
# This migration comes from alchemy (originally 20240611080918)
2+
class RenameAlchemyAttachmentFile < ActiveRecord::Migration[7.0]
3+
COLUMNS = %i[
4+
file_name
5+
file_size
6+
file_uid
7+
]
8+
9+
def change
10+
COLUMNS.each do |column|
11+
rename_column :alchemy_attachments, column, :"legacy_#{column}"
12+
end
13+
end
14+
end
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
# This migration comes from alchemy (originally 20240611080918)
2+
class RenameAlchemyPictureImageFile < ActiveRecord::Migration[7.0]
3+
COLUMNS = %i[
4+
image_file_format
5+
image_file_height
6+
image_file_name
7+
image_file_size
8+
image_file_uid
9+
image_file_width
10+
]
11+
12+
def change
13+
COLUMNS.each do |column|
14+
rename_column :alchemy_pictures, column, :"legacy_#{column}"
15+
end
16+
end
17+
end

Diff for: spec/dummy/db/schema.rb

+12-12
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
#
1111
# It's strongly recommended that you check this file into your version control system.
1212

13-
ActiveRecord::Schema[7.1].define(version: 2024_06_11_151253) do
13+
ActiveRecord::Schema[7.1].define(version: 2024_06_11_152554) do
1414
create_table "active_storage_attachments", force: :cascade do |t|
1515
t.string "name", null: false
1616
t.string "record_type", null: false
@@ -41,16 +41,16 @@
4141

4242
create_table "alchemy_attachments", force: :cascade do |t|
4343
t.string "name"
44-
t.string "file_name"
44+
t.string "legacy_file_name"
4545
t.string "file_mime_type"
46-
t.integer "file_size"
46+
t.integer "legacy_file_size"
4747
t.integer "creator_id"
4848
t.integer "updater_id"
4949
t.datetime "created_at", null: false
5050
t.datetime "updated_at", null: false
51-
t.string "file_uid"
51+
t.string "legacy_file_uid"
5252
t.index ["creator_id"], name: "index_alchemy_attachments_on_creator_id"
53-
t.index ["file_uid"], name: "index_alchemy_attachments_on_file_uid"
53+
t.index ["legacy_file_uid"], name: "index_alchemy_attachments_on_legacy_file_uid"
5454
t.index ["updater_id"], name: "index_alchemy_attachments_on_updater_id"
5555
end
5656

@@ -234,19 +234,19 @@
234234

235235
create_table "alchemy_pictures", force: :cascade do |t|
236236
t.string "name"
237-
t.string "image_file_name"
238-
t.integer "image_file_width"
239-
t.integer "image_file_height"
237+
t.string "legacy_image_file_name"
238+
t.integer "legacy_image_file_width"
239+
t.integer "legacy_image_file_height"
240240
t.datetime "created_at", null: false
241241
t.datetime "updated_at", null: false
242242
t.integer "creator_id"
243243
t.integer "updater_id"
244244
t.string "upload_hash"
245-
t.string "image_file_uid"
246-
t.integer "image_file_size"
247-
t.string "image_file_format"
245+
t.string "legacy_image_file_uid"
246+
t.integer "legacy_image_file_size"
247+
t.string "legacy_image_file_format"
248248
t.index ["creator_id"], name: "index_alchemy_pictures_on_creator_id"
249-
t.index ["image_file_name"], name: "index_alchemy_pictures_on_image_file_name"
249+
t.index ["legacy_image_file_name"], name: "index_alchemy_pictures_on_legacy_image_file_name"
250250
t.index ["name"], name: "index_alchemy_pictures_on_name"
251251
t.index ["updater_id"], name: "index_alchemy_pictures_on_updater_id"
252252
end

0 commit comments

Comments
 (0)