CarrierWave и правильное расширение файла в зависимости от его содержимого

Как я могу заставить CarrierWave добавить правильное расширение к имени файла в зависимости от его содержимого? Например, если я загружаю файл "logo" (файл PNG без расширения), CarrierWave должен сохранить его как "logo.png". А файл "img.gif" (файл JPG с неверным расширением) соответственно сохранить как "img.jpg".


person Aleksandr Shvalev    schedule 08.09.2011    source источник


Ответы (2)


Есть несколько вещей, которые вы можете сделать, в зависимости от того, используете ли вы process или version для этого.

Если это версия, в вики несущей волны есть способ сделать условные версии. https://github.com/jnicklas/carrierwave/wiki/How-to%3A-Do-conditional-processing

version :big, :if => :png? do
  process ...
end

protected
def png?(new_file)
  new_file.content_type.include? 'png'
end

Если вы используете метод process, вы можете взглянуть на это: https://gist.github.com/995663.

Добавьте их в свой код, чтобы обойти ограничения, которые есть у process.

# create a new "process_extensions" method.  It is like "process", except
# it takes an array of extensions as the first parameter, and registers
# a trampoline method which checks the extension before invocation
def self.process_extensions(*args)
  extensions = args.shift
  args.each do |arg|
    if arg.is_a?(Hash)
      arg.each do |method, args|
        processors.push([:process_trampoline, [extensions, method, args]])
      end
    else
      processors.push([:process_trampoline, [extensions, arg, []]])
    end
  end
end

# our trampoline method which only performs processing if the extension matches
def process_trampoline(extensions, method, args)
  extension = File.extname(original_filename).downcase
  extension = extension[1..-1] if extension[0,1] == '.'
  self.send(method, *args) if extensions.include?(extension)
end

Затем вы можете использовать это для вызова того, что раньше было процессом, выборочно для каждого типа файла.

PNG = %w(png)
JPG = %w(jpg jpeg)
GIF = %w(gif)
def extension_white_list
  PNG + JPG + GIF
end

process_extensions PNG, :resize_to_fit => [1024, 768]
process_extensions JPG, :... 
process_extensions GIF, :...
person keithepley    schedule 23.09.2011
comment
Следуя пути версий, что, если я хочу исправить M расширений по N версиям? Нужно ли мне иметь условия M * N, чтобы справиться с этим? - person lulalala; 21.08.2012

Проблема в том, чтобы определить правильный контент в первую очередь. Carrierwave использует гем MimeType, который определяет его MIME-тип из расширения. Поскольку в вашем случае расширение неверно, вам нужен альтернативный способ получения правильного типа mime. Это лучшее решение, которое я смог придумать, но оно зависит от способности читать файл изображения с помощью драгоценного камня RMagick.

Я столкнулся с той же проблемой, и мне пришлось переопределить метод set_content_type по умолчанию для моего загрузчика. Это предполагает, что у вас есть гем Rmagick в вашем Gemfile, так что вы можете получить правильный MIME-тип, читая изображение, а не делая наилучшее предположение.

Примечание. Это особенно полезно, если изображение используется программой Prawn, которая поддерживает только изображения JPG и PNG.

Класс загрузчика:

process :set_content_type

def set_content_type #Note we are overriding the default set_content_type_method for this uploader
  real_content_type = Magick::Image::read(file.path).first.mime_type
  if file.respond_to?(:content_type=)
    file.content_type = real_content_type
  else
    file.instance_variable_set(:@content_type, real_content_type)
  end
end

Модель изображения:

class Image < ActiveRecord::Base
  mount_uploader :image, ImageUploader

  validates_presence_of :image
  validate :validate_content_type_correctly

  before_validation :update_image_attributes

private
  def update_image_attributes
    if image.present? && image_changed?
      self.content_type = image.file.content_type
    end
  end

  def validate_content_type_correctly
    if not ['image/png', 'image/jpg'].include?(content_type)
      errors.add_to_base "Image format is not a valid JPEG or PNG."
      return false
    else
      return true
    end
  end
end

В вашем случае вы можете добавить дополнительный метод, который изменяет расширение на основе этого правильного типа mime (content_type).

person saneshark    schedule 24.10.2013