Last active
August 24, 2018 20:34
-
-
Save brand-it/854ad5cbfcc03b3c3429df4bd67401b9 to your computer and use it in GitHub Desktop.
This is a converter for Paperclip to from old url Patters to a new one. This can be helpful if you have to change maybe the bucket name or just change the path in which they are stored.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
require 'paperclip_pattern_processor' | |
processor = PaperclipPatternProcessor.new | |
Page.find_each do |page| | |
urls = page.body.scan(/"(https?:\/\/[\S]+s3.amazonaws.com[\S]+?)"/).flatten.uniq | |
urls.each do |url| | |
page.body.gsub!(url, processor.upgrade_url(url)) | |
end | |
page.save! | |
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# frozen_string_literal: true | |
# This is a converter for Paperclip to from old url Patters to a new one | |
# There is only one public method and that is #upgrade_url | |
# | |
# | |
# ===== Usage | |
# processor = PaperclipPatternProcessor.new | |
# | |
# processor.upgrade_url('https://tinderbox-dev.s3.amazonaws.com/assets/medias/26_web.jpg?1535044187') | |
# https://tinderbox-dev.s3.amazonaws.com/contents/media/26/documents/web/300ccdce-5bae-4369-bef3-60a6ddf11f03/1hQv4Ff.jpg?1535044187 | |
# | |
# | |
class PaperclipPatternProcessor | |
attr_accessor :pattern_details | |
PatternDetail = Struct.new( | |
:model, :pattern, :legacy_s3_path, :interpolator_keys, :attachment_name | |
) do | |
def uniq?(pattern_details) | |
pattern_details.find do |pattern_detail| | |
pattern_detail.model == model && pattern_detail.attachment_name == attachment_name | |
end.nil? | |
end | |
end | |
URLData = Struct.new(:pattern_detail, :path, :match_data) do | |
def model_record | |
@model_record ||= if get(:class) | |
else | |
pattern_detail.model | |
end.find_by(id: get(:id)) | |
end | |
def get(key) | |
return unless match_data.names.include?(key.to_s) | |
match_data[key].presence | |
end | |
def model | |
return if get(:class).nil? | |
get(:class).tr(' ', '_').classify.constantize | |
rescue NameError => exception | |
Rails.logger.error("PaperclipPatternProcessor - NameError: #{exception.message}") | |
nil | |
end | |
def model_invalid? | |
return true if model.present? && model != pattern_detail.model | |
return true if model_record.nil? | |
false | |
end | |
end | |
def initialize | |
Rails.application.eager_load! | |
self.pattern_details = [] | |
setup | |
end | |
# Upgrade URL will try to find a model in question and replace the new one | |
# upgrade_url('/somethings/123124/nefity.jpg') | |
# | |
# All paths require a ID in them. That is the only way to find the record needed to upgrade the URL | |
# if you don't have a ID in your path then sorry to say your out of luck. | |
# | |
def upgrade_url(url) | |
extract_data(url).each do |url_data| | |
begin | |
next if url_data.model_invalid? | |
attachment = url_data.model_record.send(url_data.pattern_detail.attachment_name) | |
return attachment.url(url_data.get(:style)) | |
rescue NoMethodError => exception | |
# This should not happen as the model_invalid? check should ensure everything responds correctly | |
Rails.logger.error( | |
"PaperclipPatternProcessor - NoMethodError: #{exception.message} #{url_data.inspect}" | |
) | |
end | |
end | |
url # if we can't update just return original URL | |
end | |
private | |
def extract_data(path) | |
find_all_matching_pattern(path).map do |pattern_detail| | |
URLData.new(pattern_detail, path, pattern_detail.pattern.match(path)) | |
end | |
end | |
def find_all_matching_pattern(path) | |
pattern_details.reject do |pattern_detail| | |
pattern_detail.pattern.match(path).nil? | |
end | |
end | |
def any_digit | |
"(?<#{__callee__}>\\d+)" | |
end | |
alias id any_digit | |
alias position any_digit | |
alias account_id any_digit | |
alias media_id any_digit | |
def document_folder | |
"(?<#{__callee__}>proposal/documents|proposal_documents)" | |
end | |
def any_non_whitespace_character | |
"(?<#{__callee__}>\\S+)" | |
end | |
alias extension any_non_whitespace_character | |
alias style any_non_whitespace_character | |
alias class any_non_whitespace_character | |
def build_pattern(path, keys) | |
pattern = path.dup | |
pattern.gsub!('.', '\.') | |
keys.each do |key| | |
value = send(key) | |
pattern.gsub!(":#{key}", value) | |
end | |
/#{pattern}/ | |
end | |
def get_keys_for_model(model, attachment_name, legacy_s3_path) | |
model.new.send(attachment_name).interpolator.all.select do |x| | |
legacy_s3_path.include?(":#{x}") | |
end | |
end | |
def build_legacy_hash(model, attachment_name, legacy_s3_path) | |
keys = get_keys_for_model(model, attachment_name, legacy_s3_path) | |
interpolator_keys.merge(keys) | |
{ | |
legacy_s3_path: legacy_s3_path, | |
interpolator_keys: keys, | |
pattern: build_pattern(legacy_s3_path, keys) | |
} | |
end | |
def real_model(model) | |
model = model.superclass while model.superclass != ActiveRecord::Base | |
model | |
end | |
def setup | |
ActiveRecord::Base.descendants.each do |model| | |
next unless model.method_defined?(:attached_file_keys) | |
model.attachment_definitions.each do |attachment_name, options| | |
next unless model.new.send(attachment_name).send(:path_option) == ':s3_path' | |
keys = get_keys_for_model(model, attachment_name, options[:legacy_s3_path]) | |
pattern_detail = PatternDetail.new( | |
real_model(model), | |
build_pattern(options[:legacy_s3_path], keys), | |
options[:legacy_s3_path], | |
keys, | |
attachment_name | |
) | |
pattern_details.push(pattern_detail) if pattern_detail.uniq?(pattern_details) | |
end | |
end | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
This code requires rails. has been tested using Rails 4.2.