Skip to content

Instantly share code, notes, and snippets.

@brianlittmann
Last active May 26, 2016 17:38
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save brianlittmann/241c73c5c13488e39b6befb450f5dc16 to your computer and use it in GitHub Desktop.
Save brianlittmann/241c73c5c13488e39b6befb450f5dc16 to your computer and use it in GitHub Desktop.
Save image versions with Refile with streaming as a fallback
class AwsUploader
CLIENT = Aws::S3::Client.new
BUCKET = Rails.configuration.x.aws["output_bucket"]
def self.upload(file, key)
CLIENT.put_object({
bucket: BUCKET,
key: key,
body: file,
content_length: file.size
})
end
def self.delete(key)
resp = CLIENT.list_objects({
bucket: BUCKET,
prefix: key
})
CLIENT.delete_objects({
bucket: BUCKET,
delete: {
objects: resp.contents.map{|c| c.to_hash.slice(:key)}
}
})
end
end
class CacheThumbnailsJob < ActiveJob::Base
queue_as :default
def perform(post)
versions = {}
extension = post.thumbnail_attacher.extension
source_file = Refile.store.get(post.thumbnail_id).download
Post.thumbnails.each do |k, attrs|
filename = "#{k}.#{extension}"
key = [post.thumbnail_prefix, filename].join("/")
file = Refile.processors[attrs[:processor]].call(source_file, attrs[:width], attrs[:height])
AwsUploader.upload(file, key)
versions[k] = filename
end
# thumbnail_versions is an hstore column
post.update(thumbnail_versions: versions)
end
end
class DeleteThumbnailsJob < ActiveJob::Base
queue_as :default
def perform(key)
AwsUploader.delete(key)
end
end
class Post < ActiveRecord::Base
attachment :thumbnail, type: :image
def self.thumbnails
@thumbnails ||= {
md: {
processor: "fill",
width: 480,
height: 270
},
md2x: {
processor: "fill",
width: 960,
height: 540
}
}
end
after_save :cache_thumbnails
def thumbnail_prefix(key=nil)
['thumbnails', (key || thumbnail_id)].join('/')
end
private
def cache_thumbnails
if thumbnail_id_changed?
CacheThumbnailsJob.perform_later(self) if thumbnail_id.present?
DeleteThumbnailsJob.perform_later(thumbnail_prefix(thumbnail_id_was)) if thumbnail_id_was.present?
end
end
end
module PostsHelper
def thumbnail_url(post, version)
filename = post.thumbnail_versions[version.to_s]
if filename.present?
[Rails.configuration.x.cdn_host, post.thumbnail_prefix, filename].join('/')
else
# Fallback to Refile URL if not generated yet
specs = Post.thumbnails[version]
attachment_url(post, :thumbnail, specs[:processor], specs[:width], specs[:height])
end
end
end
@peterfication
Copy link

This looks nice. I will try to adopt it.

But I don't want the jobs to run. I'd rather delete all thumbnails after let's say 30 days and the call to a thumbnail checks if it exists and if not generates it. I don't know if this is possible. What do you think?

@brianlittmann
Copy link
Author

You could have a cron job that runs a Rake task which uses the AWS SDK to check if an object exists, and if not generate some thumbnails. In regards to deleting old thumbnails, you'd either need to keep track of the old image hashes/filenames or run some sort of diff on what's in your local database vs. what's listed in S3 and delete anything in S3 that isn't stored locally (which sounds kinda clunky).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment