Instantly share code, notes, and snippets.

Embed
What would you like to do?
Work around for files getting uploaded as application/octet-stream
class ApplicationController < ActionController::Base
# omitted stuff
private
# Used to correct content type for files uploaded with bulkupload or from PicMonkey
def correct_content_type_for_octet_stream(filedata)
return nil if filedata.blank?
# see what the unix file command thinks this is
if filedata.content_type == 'application/octet-stream'
filedata.content_type = type_from_file_command(filedata.path)
end
# 'file' thinks new Office docs are zip files, so we may need to correct what we just did above
if filedata.content_type =~ /application\/(x-)?zip/
filedata.content_type = type_from_file_extension(filedata.original_filename)
end
filedata
end
def type_from_file_command(file)
Paperclip::FileCommandContentTypeDetector.new(file).detect
end
def type_from_file_extension(filename)
Paperclip::ContentTypeDetector.new(filename).send(:possible_types).first
end
end
class DocumentsController < ApplicationController
before_action :set_document, only: [:edit, :update, :destroy]
# .... omitted
# POST /documents
def create
@document = Document.new(document_params)
@document.file = correct_content_type_for_octet_stream(params[:document][:file])
if @document.save
redirect_to document_category_path(id: @document.document_category_id), notice: 'Document was successfully created.'
else
render :new
end
end
# PUT /documents/1
def update
@document.file = correct_content_type_for_octet_stream(params[:document][:file]) unless params[:document][:file].blank?
if @document.update_attributes(document_params)
redirect_to document_path(@document), notice: 'Document was successfully updated.'
else
render :edit
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_document
@document = Document.find(params[:id])
end
# Only allow a trusted parameter "white list" through.
def document_params
params.require(:document).permit(:document_category_id, :campus_only, :login_only)
end
end
class Document < ActiveRecord::Base
belongs_to :category, :class_name => 'DocumentCategory', :foreign_key => 'document_category_id'
# Store documents in S3 - one bucket for all CMS instances - subfolders for each site
has_attached_file :file,
:storage => :s3,
:s3_credentials => "#{Rails.root}/config/amazon_s3.yml",
:s3_permissions => "authenticated-read",
:path => "#{SiteConfig.hostname}/:class/:id_partition/:filename",
:filename_cleaner => PaperclipModifications::FilenameCleaner.new
validates_attachment :file, :presence => true, :size => { :less_than => 100.megabytes },
:content_type => { :content_type => [/\Aimage\/.*\Z/, /\Aapplication\/.*\Z/, /\Atext\/.*\Z/]}
end
# Allow type mismatch for Office documents - our version of `file` calls all of them zip files
if Object::RUBY_PLATFORM =~ /darwin/
Paperclip.options[:content_type_mappings] = {
:docx => "application/zip",
:xlsx => "application/zip",
:pptx => "application/zip",
:pages => "application/zip",
:numbers => "application/zip",
:key => "application/zip"
}
else
Paperclip.options[:content_type_mappings] = {
:docx => "application/x-zip",
:xlsx => "application/x-zip",
:pptx => "application/x-zip",
:pages => "application/x-zip",
:numbers => "application/x-zip",
:key => "application/x-zip"
}
end
module Paperclip
class MediaTypeSpoofDetector
# Make spoof detection stricter - original only compared type so all 'application' types matched all others
def media_type_mismatch?
! supplied_file_content_types.include?(calculated_content_type)
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment