Skip to content

Instantly share code, notes, and snippets.

@absk1317
Last active August 20, 2020 09:12
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save absk1317/9634e0008d7ed099209a7d7093aaf384 to your computer and use it in GitHub Desktop.
Save absk1317/9634e0008d7ed099209a7d7093aaf384 to your computer and use it in GitHub Desktop.
Async Image Processing
# frozen_string_literal: true
# == Schema Information
#
# Table name: images
#
# id :bigint not null, primary key
# deleted_at :datetime indexed
# height :decimal(, )
# image :string
# temp_image :string not null
# width :decimal(, )
# created_at :datetime not null
# updated_at :datetime not null
#
# Indexes
#
# index_images_on_deleted_at (deleted_at)
#
# Image ORM
class Image < ApplicationRecord
include RailsAdmin::Image
acts_as_paranoid
MAX_ALLOWED_FILE_SIZE = 14
mount_uploader :temp_image, TempImageUploader
mount_uploader :image, ImageUploader
has_many :image_uploads, dependent: :destroy
after_commit :create_versions, on: :create
validate :temp_image_presence, :file_size
validate :image_dimensions, on: :create
attr_accessor :creation_token
def url
image&.url || temp_image.url
end
alias original_image_url url
alias upload_id id
%w[logo medium onesignal].each do |version_type|
define_method "#{version_type}_version_url" do
return temp_image.url unless image&.send(version_type)&.url
image.send(version_type).url
end
end
def image_json
{ upload_id: id,
original_image_url: url,
medium_version_url: medium_version_url,
logo_version_url: logo_version_url,
width: width.to_i,
height: height.to_i }
end
def file_size
upload_limit = MAX_ALLOWED_FILE_SIZE.to_f
return unless temp_image.file&.size.to_f / (1000 * 1000) > upload_limit
errors.add(:image, I18n.t('images.errors.size', upload_limit: upload_limit))
end
def create_versions
::ImageProcessingWorker.perform_async(id)
end
def temp_image_presence
# didn't use validates :temp_image, presence: true because wanted to add error to image, not temp image
errors.add(:image, "can't be blank") unless temp_image.present?
end
def image_dimensions
return if admin_edit.to_s == '1'
return if width.to_i > 120 && height.to_i > 120
errors.add(:image, I18n.t('images.errors.dimensions'))
end
end
# frozen_string_literal: true
class ImageProcessingWorker
include Sidekiq::Worker
sidekiq_options queue: 'default', retry: 10
def perform(upload_id)
object = Image.find(upload_id)
return if object.image.present?
object.image = object.temp_image
object.save
## use sidekiq backoff instead of managing manaully. Wouldn't be triggered in most of the times.
raise ActiveRecord::RecordInvalid unless object.image.present?
end
end
# frozen_string_literal: true
require 'rails_helper'
describe ImageProcessingWorker do
it 'updates image column with temp image column' do
Sidekiq::Testing.inline!
image = Image.create!(temp_image: fixture_file_upload('test_image.jpg', 'image/jpg'))
expect(image.image.present?).to eq(false)
expect(image.temp_image.present?).to eq(true)
ImageProcessingWorker.perform_async(image.id)
expect(image.reload.image.present?).to eq(true) # adds the image
expect(image.reload.temp_image.present?).to eq(true)
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment