Paperclip

Gem, который служит для проверки вложений в рельсах.

application/octet-stream

Поскольку для определения типа файла используется приложение file, которую в свою очередь использует libmagick - она знает не обо всех типах файлов, которые существуют в мире.

MIME тип application/octet-stream проставляется для тех файлов, тип которых не получается определить. В GEM'е же на эту тему есть предохранитель, чтобы нельзя было просунуть абы какой тип файлов под видом application/octet-stream. Вычитка кода модуля навела на то, что кроме проверки самого типа файла производится определение MIME типа с помощью GEM'а mime-type. Ошибка выдаётся в случае, если тип application/octet-stream, а MIME::Types.types_for не вернул для проверяемого файла ни одного вхождения.

Например тип файл с расширением vsdx определяется как application/vnd.ms-visio.drawing.main+xml, однако libmagick о таком типе к сожалению не знает, как и MIME::Types.

Решение довольно простое:

  • Добавить в MIME::Types новый тип
  • Добавить в список разрешённых типов paperclip application/octet-stream

Чтобы каждый раз по менеджерской прихоти не выкатывать новую ревизию кода было решено вынести данный функционал в конфиги, что в конечно итоге вылилось в следующие куски кода:

config/initializers/paperclip.rb
unless Rails.configuration.portal['paperclip'].nil?
  mime_rewrite = Rails.configuration.portal['paperclip']['mime'] || []
 
  mime_rewrite.each do |ext,mime|
    t = MIME::Type.new(mime)
    t.extensions = ext
    MIME::Types.add(t)
    MIME::Types.index_extensions(t)
  end
end
config/portal.yml
paperclip:
  mime:
    vsdx: 'application/vnd.ms-visio.drawing.main+xml'

attachments:
  filesize: 20
  mime:
    - 'application/gzip'
    - 'application/octet-stream'
    - 'application/pdf'
    - 'text/plain'
app/models/order.rb
unless Rails.configuration.portal['attachments'].nil?
  validates_attachment :attachment_file, size: { less_than_or_equal_to: Rails.configuration.portal['attachments']['filesize'].to_i.megabytes }, content_type: { content_type: Rails.configuration.portal['attachments']['mime'] || []}
end

Неточности документации

Проблема с интернационализацией

В документации к paperclip-i18n написано, что для ошибки с неправильным типом файла требуется поправить следующее поле в файле интернационализации

ru:
  errors:
    messages:
      spoofed_media_type: "имеет содержимое, не соответствующее заявленному"

Однако достаточно продолжительные исследования выявили следующее

I18N keys: [:ru, :activerecord, :attributes, :order, :attachment_file_content_type]
I18N keys: [:ru, :attributes, :attachment_file_content_type]
I18N keys: [:ru, :activerecord, :errors, :models, :order, :attributes, :attachment_file_content_type, :invalid]
I18N keys: [:ru, :activerecord, :errors, :models, :order, :invalid]
I18N keys: [:ru, :activerecord, :errors, :messages, :invalid]
     => имеет неверное значение

Будьте внимательны и осторожны, описание ошибки должно быть в формате, например

ru:
  activerecord:
    errors:
      models:
        order:
          attributes:
            <parameter_name>_<check_type>:
              invalid: <error_message>

или

ru:
  attributes:
    <parameter_name>_<check_type>: <error_message>

Где check_type - тип проверки, в которой произошла ошибка (например size или content_type)