class MiniPaperclip::Attachment

Constants

UnsupportedError

Attributes

attachment_name[R]
config[R]
meta_content_type[R]
record[R]
storage[R]
waiting_write_file[R]

Public Class Methods

new(record, attachment_name, overwrite_config = {}) click to toggle source
# File lib/mini_paperclip/attachment.rb, line 10
def initialize(record, attachment_name, overwrite_config = {})
  @record = record
  @attachment_name = attachment_name
  @config = MiniPaperclip.config.merge(overwrite_config)
  @waiting_write_file = nil
  @meta_content_type = nil
  @dirty = false
  @storage = Storage.const_get(@config.storage.to_s.camelcase)
                    .new(self, @config)
end

Public Instance Methods

animated?() click to toggle source
# File lib/mini_paperclip/attachment.rb, line 150
def animated?
  content_type == 'image/gif'
end
assign(file) click to toggle source
# File lib/mini_paperclip/attachment.rb, line 58
def assign(file)
  @dirty = true
  @waiting_copy_attachment = nil
  @waiting_write_file = nil
  @meta_content_type = nil

  if present?
    push_delete_files
  end

  if file.nil?
    assign_nil
  elsif file.instance_of?(Attachment)
    if file.present?
      assign_attachment(file)
    else
      assign_nil
    end
  elsif file.respond_to?(:original_filename)
    assign_uploaded_file(file)
  elsif file.respond_to?(:path)
    assign_file(file)
  elsif file.instance_of?(String)
    if file.empty?
      # do nothing
    elsif file.start_with?('http')
      assign_http(file)
    elsif file.start_with?('data:')
      assign_data_uri(file)
    else
      raise UnsupportedError, "attachment for \"#{file[0..100]}\" is not supported"
    end
  else
    raise UnsupportedError, "attachment for #{file.class} is not supported"
  end
end
blank?() click to toggle source
# File lib/mini_paperclip/attachment.rb, line 42
def blank?
  !file?
end
content_type() click to toggle source
# File lib/mini_paperclip/attachment.rb, line 25
def content_type
  @record.read_attribute("#{@attachment_name}_content_type")
end
dirty?() click to toggle source
# File lib/mini_paperclip/attachment.rb, line 54
def dirty?
  @dirty
end
do_delete_files() click to toggle source
# File lib/mini_paperclip/attachment.rb, line 146
def do_delete_files
  @storage.do_delete_files
end
exists?(style = :original) click to toggle source
# File lib/mini_paperclip/attachment.rb, line 46
def exists?(style = :original)
  file? && @storage.exists?(style)
end
file?() click to toggle source
# File lib/mini_paperclip/attachment.rb, line 37
def file?
  original_filename.present?
end
Also aliased as: present?
original_filename() click to toggle source
# File lib/mini_paperclip/attachment.rb, line 21
def original_filename
  @record.read_attribute("#{@attachment_name}_file_name")
end
present?()
Alias for: file?
process_and_store() click to toggle source
# File lib/mini_paperclip/attachment.rb, line 95
def process_and_store
  return unless file?
  return unless @waiting_write_file

  begin
    debug("start attachment styles process")
    @storage.write(:original, @waiting_write_file)
    @config.styles&.each do |style, size_arg|
      Tempfile.create([style.to_s, File.extname(@waiting_write_file.path)]) do |temp|
        temp.binmode
        MiniMagick::Tool::Convert.new do |convert|
          convert << @waiting_write_file.path
          convert.coalesce if animated?
          convert.auto_orient
          if size_arg.end_with?('#')
            # crop option
            convert.resize("#{size_arg[0..-2]}^")
            convert.gravity("center")
            convert.extent(size_arg[0..-2])
          else
            convert.resize(size_arg)
          end
          convert.layers("optimize") if animated?
          convert << temp.path
        end
        @storage.write(style, temp)
      end
    end

    # should delete after write for copy
    if !@config.keep_old_files
      do_delete_files
    end
  
  ensure
    if @waiting_write_file.respond_to?(:close!)
      @waiting_write_file.close!
    elsif @waiting_write_file.respond_to?(:close)
      @waiting_write_file.close
    end
  end
  @waiting_write_file = nil
end
push_delete_files() click to toggle source
# File lib/mini_paperclip/attachment.rb, line 139
def push_delete_files
  @storage.push_delete_file(:original)
  @config.styles&.each_key do |style|
    @storage.push_delete_file(style)
  end
end
size() click to toggle source
# File lib/mini_paperclip/attachment.rb, line 29
def size
  @record.read_attribute("#{@attachment_name}_file_size")
end
updated_at() click to toggle source
# File lib/mini_paperclip/attachment.rb, line 33
def updated_at
  @record.read_attribute("#{@attachment_name}_updated_at")
end
url(style = :original) click to toggle source
# File lib/mini_paperclip/attachment.rb, line 50
def url(style = :original)
  @storage.url_for_read(style)
end

Private Instance Methods

assign_attachment(attachment) click to toggle source
# File lib/mini_paperclip/attachment.rb, line 164
def assign_attachment(attachment)
  # copy
  @waiting_write_file = attachment.storage.open(:original)
  @record.write_attribute("#{@attachment_name}_file_name", attachment.original_filename)
  @record.write_attribute("#{@attachment_name}_content_type", attachment.content_type)
  @record.write_attribute("#{@attachment_name}_file_size", attachment.size)
  @record.write_attribute("#{@attachment_name}_updated_at", Time.current)
end
assign_data_uri(data_uri) click to toggle source
# File lib/mini_paperclip/attachment.rb, line 208
def assign_data_uri(data_uri)
  # data-uri
  match_data = data_uri.match(/\Adata:([-\w]+\/[-\w\+\.]+)?;base64,(.*)/m)
  if match_data.nil?
    raise UnsupportedError, "attachment for \"#{data_uri[0..100]}\" is not supported"
  end
  raw = Base64.decode64(match_data[2])
  @record.write_attribute("#{@attachment_name}_file_name", nil)
  @record.write_attribute("#{@attachment_name}_content_type", strict_content_type(StringIO.new(raw)))
  @record.write_attribute("#{@attachment_name}_file_size", raw.bytesize)
  @record.write_attribute("#{@attachment_name}_updated_at", Time.current)
  @waiting_write_file = build_tempfile(StringIO.new(raw))
  @meta_content_type = match_data[1]
end
assign_file(file) click to toggle source
# File lib/mini_paperclip/attachment.rb, line 183
def assign_file(file)
  # e.g. File
  @record.write_attribute("#{@attachment_name}_file_name", File.basename(file.path))
  @record.write_attribute("#{@attachment_name}_content_type", strict_content_type(file))
  @record.write_attribute("#{@attachment_name}_file_size", file.size)
  @record.write_attribute("#{@attachment_name}_updated_at", Time.current)
  @waiting_write_file = build_tempfile(file.tap(&:rewind))
end
assign_http(url) click to toggle source
# File lib/mini_paperclip/attachment.rb, line 192
def assign_http(url)
  # download from url
  open_uri_option = {
    read_timeout: MiniPaperclip.config.read_timeout || 60
  }
  uri = URI.parse(url)
  uri.open(open_uri_option) do |io|
    @record.write_attribute("#{@attachment_name}_file_name", File.basename(uri.path))
    @record.write_attribute("#{@attachment_name}_content_type", strict_content_type(io))
    @record.write_attribute("#{@attachment_name}_file_size", io.size)
    @record.write_attribute("#{@attachment_name}_updated_at", Time.current)
    @waiting_write_file = build_tempfile(io.tap(&:rewind))
    @meta_content_type = io.meta["content-type"]
  end
end
assign_nil() click to toggle source
# File lib/mini_paperclip/attachment.rb, line 156
def assign_nil
  # clear
  @record.write_attribute("#{@attachment_name}_file_name", nil)
  @record.write_attribute("#{@attachment_name}_content_type", nil)
  @record.write_attribute("#{@attachment_name}_file_size", nil)
  @record.write_attribute("#{@attachment_name}_updated_at", nil)
end
assign_uploaded_file(file) click to toggle source
# File lib/mini_paperclip/attachment.rb, line 173
def assign_uploaded_file(file)
  # e.g. ActionDispatch::Http::UploadedFile
  @record.write_attribute("#{@attachment_name}_file_name", file.original_filename)
  @record.write_attribute("#{@attachment_name}_content_type", strict_content_type(file.to_io))
  @record.write_attribute("#{@attachment_name}_file_size", file.size)
  @record.write_attribute("#{@attachment_name}_updated_at", Time.current)
  @waiting_write_file = build_tempfile(file.tap(&:rewind))
  @meta_content_type = file.content_type
end
build_tempfile(io) click to toggle source
# File lib/mini_paperclip/attachment.rb, line 228
def build_tempfile(io)
  temp = Tempfile.new(['MiniPaperclip'])
  temp.binmode
  debug("copying by tempfile from:#{io.class} to:#{temp.path}")
  IO.copy_stream(io, temp)
  temp.rewind
  temp
end
debug(str) click to toggle source
# File lib/mini_paperclip/attachment.rb, line 237
def debug(str)
  MiniPaperclip.config.logger.debug("[mini_paperclip] #{str}")
end
strict_content_type(io) click to toggle source
# File lib/mini_paperclip/attachment.rb, line 223
def strict_content_type(io)
  io.rewind
  MimeMagic.by_magic(io)&.type
end