Your Teacher
Chris Oliver
Hi, I'm Chris. I'm the creator of GoRails, Hatchbox.io and Jumpstart. I spend my time creating tutorials and tools to help Ruby on Rails developers build apps better and faster.
About This Episode
Now that the Paperclip gem has been deprecated, it's recommended that you migrate your apps to ActiveStorage
Notes
Resources
db/migrate/convert_to_active_storage.rb
Dir[Rails.root.join("app/models/**/*.rb")].sort.each { |file| require file }
class ConvertToActiveStorage < ActiveRecord::Migration[5.2]
require 'open-uri'
def up
# postgres
# get_blob_id = 'LASTVAL()'
# mysql / mariadb
# get_blob_id = 'LAST_INSERT_ID()'
# sqlite
get_blob_id = 'LAST_INSERT_ROWID()'
active_storage_blob_statement = ActiveRecord::Base.connection.raw_connection.prepare(<<-SQL)
INSERT INTO active_storage_blobs (
key, filename, content_type, metadata, byte_size,
checksum, created_at
) VALUES (?, ?, ?, '{}', ?, ?, ?)
SQL
active_storage_attachment_statement = ActiveRecord::Base.connection.raw_connection.prepare(<<-SQL)
INSERT INTO active_storage_attachments (
name, record_type, record_id, blob_id, created_at
) VALUES (?, ?, ?, #{get_blob_id}, ?)
SQL
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
model.find_each.each do |instance|
attachments.each do |attachment|
if instance.send(attachment).exists?
active_storage_blob_statement.execute(
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
)
active_storage_attachment_statement.
execute(attachment, model.name, instance.id, instance.updated_at.iso8601)
end
end
end
end
end
active_storage_attachment_statement.close
active_storage_blob_statement.close
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
lib/tasks/paperclip.rake
namespace :paperclip do
task migrate: :environment do
klass = User
attachment = 'avatar'
name_field = :"#{attachment}_file_name"
klass.where.not(name_field => nil).find_each do |instance|
# This step helps us catch any attachments we might have uploaded that
# don't have an explicit file extension in the filename
filename = instance.send("#{attachment}_file_name")
next if filename.blank?
id = instance.id
id_partition = ("%09d".freeze % id).scan(/\d{3}/).join("/".freeze)
url = "https://nyc3.digitaloceanspaces.com/gorails/#{klass.table_name}/#{attachment.pluralize}/#{id_partition}/original/#{filename}"
instance.send(attachment.to_sym).attach(
io: open(url),
filename: instance.send(name_field),
content_type: instance.send(:"#{attachment}_content_type")
)
end
end
end
Popular Rails Gems
0% Complete
1
Styling with Bootstrap Sass
14m
2
Debugging With BetterErrors
5m
3
Pretty urls with FriendlyID
22m
4
Pagination with will_paginate
9m
5
File Uploading with Carrierwave
23m
6
User Authentication with Devise
19m
7
Keeping track with Annotate
6m
8
Sending emails with Mandrill
32m
9
Authorization With CanCanCan
23m
10
Authorization with Pundit
20m
11
Soft Delete with Paranoia
16m
12
Newsletter Sign Up Form with country_select
18m
13
The State_Machine Gem
26m
14
Using ActiveAdmin to Build an Admin UI
17m
How to Migrate from Paperclip to Rails ActiveStorage
27m
16
Components with Phlex in Rails
25m