Migration to Shrine attachment handling

This commit is contained in:
Christoph Haas 2020-11-01 15:07:16 +01:00
parent 2d53397dda
commit c4f5741b0c
13 changed files with 175 additions and 181 deletions

View file

@ -1,105 +0,0 @@
# Convert the screenshots from the deprecated Paperclip gem schema
# to the new ActiveStorage schema built into Rails 5.2.
Dir[Rails.root.join("app/models/**/*.rb")].sort.each { |file| require file }
class ConvertToActiveStorage < ActiveRecord::Migration[5.2]
require 'open-uri'
def up
puts "Running up..."
# postgres
get_blob_id = 'LASTVAL()'
# mysql / mariadb
# get_blob_id = 'LAST_INSERT_ID()'
# sqlite
# get_blob_id = 'LAST_INSERT_ROWID()'
puts "Preparing queries"
active_storage_blob_statement = ActiveRecord::Base.connection.raw_connection.prepare('active_storage_blob_statement', <<-SQL)
INSERT INTO active_storage_blobs (
key, filename, content_type, metadata, byte_size, checksum, created_at
) VALUES ($1, $2, $3, '{}', $4, $5, $6)
SQL
active_storage_attachment_statement = ActiveRecord::Base.connection.raw_connection.prepare('active_storage_attachment_statement', <<-SQL)
INSERT INTO active_storage_attachments (
name, record_type, record_id, blob_id, created_at
) VALUES ($1, $2, $3, #{get_blob_id}, $4)
SQL
Rails.application.eager_load!
models = ActiveRecord::Base.descendants.reject(&:abstract_class?)
transaction do
models.each do |model|
attachments = model.column_names.map do |c|
if c =~ /(.+)_file_name$/
$1
end
end.compact
if attachments.blank?
next
end
model.find_each.each do |instance|
puts "Model: #{instance}"
attachments.each do |attachment|
puts "Attachment: #{attachment}"
if instance.send(attachment).path.blank?
next
end
ActiveRecord::Base.connection.raw_connection.exec_prepared(
'active_storage_blob_statement', [
key(instance, attachment),
instance.send("#{attachment}_file_name"),
instance.send("#{attachment}_content_type"),
instance.send("#{attachment}_file_size"),
checksum(instance.send(attachment)),
instance.updated_at.iso8601
])
ActiveRecord::Base.connection.raw_connection.exec_prepared(
'active_storage_attachment_statement', [
attachment,
model.name,
instance.id,
instance.updated_at.iso8601,
])
end
end
end
end
end
def down
raise ActiveRecord::IrreversibleMigration
end
private
def key(instance, attachment)
SecureRandom.uuid
# Alternatively:
# filename = instance.send("#{attachment}_file_name")
# klass = instance.class.table_name
# id = instance.id
# id_partition = ("%09d".freeze % id).scan(/\d{3}/).join("/".freeze)
# "#{klass}/#{attachment.pluralize}/#{id_partition}/original/#{filename}"
end
def checksum(attachment)
# local files stored on disk:
url = attachment.path
Digest::MD5.base64digest(File.read(url))
# remote files stored on another person's computer:
# url = attachment.url
# Digest::MD5.base64digest(Net::HTTP.get(URI(url)))
end
end

View file

@ -0,0 +1,5 @@
class AddShrineImageDataToScreenshot < ActiveRecord::Migration[6.0]
def change
add_column :screenshots, :simage_data, :text
end
end

View file

@ -10,7 +10,7 @@
#
# It's strongly recommended that you check this file into your version control system.
ActiveRecord::Schema.define(version: 2020_10_01_000000) do
ActiveRecord::Schema.define(version: 2020_10_31_112024) do
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
@ -99,6 +99,7 @@ ActiveRecord::Schema.define(version: 2020_10_01_000000) do
t.datetime "image_updated_at"
t.string "image_fingerprint"
t.integer "user_id", default: 0
t.text "image_data"
t.index ["id", "approved"], name: "id_approved"
t.index ["id", "uploaderhash"], name: "id_uploaderhash"
end