I am frequently getting this error Memory quota exceeded for my ruby on rails application hosted on heroku:
2014-12-29 11:09:37.876 355 <45>1 2014-12-29T11:09:37.210533+00:00 heroku worker.1 - - source=worker.1 dyno=heroku.22144543.00c11b4d-8ec6-46d9-addf-f03163e10f0c sample#memory_total=2899.25MB sample#memory_rss=1023.73MB sample#memory_cache=0.00MB sample#memory_swap=1875.52MB sample#memory_pgpgin=2603236pages sample#memory_pgpgout=2341160pages
2014-12-29 11:09:37.876 132 <4
2014-12-29 11:09:37.876 132 <455>1 2014-12-29T11:09:37.210533+00:00 heroku worker.1 - - Process running mem=2899M(283.1%)>1 2014-12-29T11:09:37.210533+00:00 heroku worker.1 - - Error R14 (Memory quota exceeded)
I read the blog of which suggests the solution i.e. set WEB_CONCURRENCY config variable but it is not clear to me.
My current configuration on heroku are:
config/unicorn.rb
worker_processes Integer(ENV["WEB_CONCURRENCY"] || 3)
timeout 29
preload_app true
Edited:
Worker Code
class PhotoWorker
include Sidekiq::Worker
sidekiq_options queue: "high"
# sidekiq_options retry: false
def perform(params)
begin
puts "Start Woker for #{params.inspect}"
site = Site.find params['site_id']
if params["id"].present?
photo = Photo.find(params["id"])
if params['key'].present?
photo.key = params['key']
photo.remote_image_url = photo.image.direct_fog_url(:with_path => true)
photo.image_name = params['key'].split('/').last
photo.save(validate: false)
puts photo.inspect
end
else
#photo = site.photos.build
#photo.hotel_detail_id = site.hotel_detail.id
#photo.album_id = site.hotel_detail.album.id
#photo.save(validate: false)
photo.key = params['key']
photo.remote_image_url = photo.image.direct_fog_url(:with_path => true)
#photo.image = params['key']
#photo.remote_image_url = params['key']
photo.image_name = params['key'].split('/').last
puts photo.inspect
photo.save(validate: false)
end
if params["id"].present? && params["crop_x"].present?
photo.crop_x = params["crop_x"]
photo.crop_y = params["crop_y"]
photo.crop_w = params["crop_w"]
photo.crop_h = params["crop_h"]
photo.save(validate: false)
end
if params["id"].present?
if params['key'].present?
s3 = AWS::S3.new.buckets[ENV["FOG_DIRECTORY"]]
s3.objects[params['key']].delete
end
else
AmazonFile.new(params['key']).delete
end
puts "Deleted temp file: #{params['key']}" if params['key'].present?
puts "Photo(#{photo.id}) saved successfully. URL: #{params['key']}"
rescue Exception => exc
#puts "Photo not saved. URL: #{params['key']}"
puts "Error: #{exc.message}"
end
end
end
Apart from sidekiq i am also using carrierwave_backgrounder gem.
I am using Kraken for image compression
Photo Uploader
class PhotoUploader < CarrierWave::Uploader::Base
#include ::CarrierWave::Backgrounder::Delay
include CarrierWaveDirect::Uploader
include CarrierWave::MiniMagick
include CarrierWave::MimeTypes
process :set_content_type
process :crop
storage :fog
after :store, :kraken
version :admin do
process :resize_to_fit => [200,200]
end
#Leisure theme
version :leisure_358x243, :if => :leisure_theme? do
process :resize_to_fill => [358,243]
end
version :leisure_900x500, :if => :leisure_theme? do
process :resize_to_fill => [900,500]
end
version :leisure_350x147, :if => :leisure_theme? do
process :resize_to_fill => [350,147]
end
version :leisure_1100x344, :if => :leisure_theme? do
process :resize_to_fill => [1100,344]
end
#Business theme
version :business_360x160, :if => :business_theme? do
process :resize_to_fill => [360,160]
end
version :business_1100x315, :if => :business_theme? do
process :resize_to_fill => [1100,315]
end
version :business_1140x530, :if => :business_theme? do
process :resize_to_fill => [1140,530]
end
version :business_1100x355, :if => :business_theme? do
process :resize_to_fill => [1100,355]
end
#Commthree theme
version :commthree_550x300, :if => :commthree_theme? do
process :resize_to_fill => [550,300]
end
version :commthree_319x183, :if => :commthree_theme? do
process :resize_to_fill => [319,183]
end
version :commthree_1920x700, :if => :commthree_theme? do
process :resize_to_fill => [1920,700]
end
#All theme
version :all_360x188 do
process :resize_to_fill => [360,188]
end
version :all_1100x401 do
process :resize_to_fill => [1100,401]
end
version :all_140x88 do
process :resize_to_fill => [140,88]
end
def kraken(file)
if version_name.to_s == ""
storepath = store_dir + "/" + filename
else
fname = filename.split('.')
#originalfile = "http://s3.amazonaws.com/" + ENV["FOG_DIRECTORY"] + "/" + store_dir + "/" + fname[0] + "_" + version_name.to_s + "." + fname.last
storepath = store_dir + "/" + fname[0] + "_" + version_name.to_s + "." + fname.last
end
originalfile = "http://s3.amazonaws.com/" + ENV["FOG_DIRECTORY"] + "/" + store_dir + "/" + filename
kraken = Kraken::API.new(
:api_key => ENV['KRAKEN_API'],
:api_secret => ENV['KRAKEN_SECRET']
)
params = {}
Rails.logger.info('Kraken About to Process: ' + originalfile);
p "version #{version_name}"
case version_name.to_s
when "admin"
params = {
'lossy' => true,
'resize' => {
'width' => 200,
'height' => 200,
'strategy' => "auto",
},
's3_store' => {
'key' => ENV['AWS_ACCESS_KEY_ID'],
'secret' => ENV["AWS_SECRET_ACCESS_KEY"],
'bucket' => ENV["FOG_DIRECTORY"],
'acl' => 'public_read',
'path' => storepath
},
}
when "leisure_358x243"
params = {
'lossy' => true,
'resize' => {
'width' => 358,
'height' => 243,
'strategy' => "fit",
},
's3_store' => {
'key' => ENV['AWS_ACCESS_KEY_ID'],
'secret' => ENV["AWS_SECRET_ACCESS_KEY"],
'bucket' => ENV["FOG_DIRECTORY"],
'acl' => 'public_read',
'path' => storepath
},
}
when "leisure_900x500"
params = {
'lossy' => true,
'resize' => {
'width' => 900,
'height' => 500,
'strategy' => "fit",
},
's3_store' => {
'key' => ENV['AWS_ACCESS_KEY_ID'],
'secret' => ENV["AWS_SECRET_ACCESS_KEY"],
'bucket' => ENV["FOG_DIRECTORY"],
'acl' => 'public_read',
'path' => storepath
},
}
when "leisure_350x147"
params = {
'lossy' => true,
'resize' => {
'width' => 350,
'height' => 147,
'strategy' => "exact",
},
's3_store' => {
'key' => ENV['AWS_ACCESS_KEY_ID'],
'secret' => ENV["AWS_SECRET_ACCESS_KEY"],
'bucket' => ENV["FOG_DIRECTORY"],
'acl' => 'public_read',
'path' => storepath
},
}
when "leisure_1100x344"
params = {
'lossy' => true,
'resize' => {
'width' => 1100,
'height' => 344,
'strategy' => "fit",
},
's3_store' => {
'key' => ENV['AWS_ACCESS_KEY_ID'],
'secret' => ENV["AWS_SECRET_ACCESS_KEY"],
'bucket' => ENV["FOG_DIRECTORY"],
'acl' => 'public_read',
'path' => storepath
},
}
when "business_360x160"
params = {
'lossy' => true,
'resize' => {
'width' => 360,
'height' => 160,
'strategy' => "fit",
},
's3_store' => {
'key' => ENV['AWS_ACCESS_KEY_ID'],
'secret' => ENV["AWS_SECRET_ACCESS_KEY"],
'bucket' => ENV["FOG_DIRECTORY"],
'acl' => 'public_read',
'path' => storepath
},
}
when "business_1100x315"
params = {
'lossy' => true,
'resize' => {
'width' => 1100,
'height' => 315,
'strategy' => "fit",
},
's3_store' => {
'key' => ENV['AWS_ACCESS_KEY_ID'],
'secret' => ENV["AWS_SECRET_ACCESS_KEY"],
'bucket' => ENV["FOG_DIRECTORY"],
'acl' => 'public_read',
'path' => storepath
},
}
when "business_1140x530"
params = {
'lossy' => true,
'resize' => {
'width' => 1140,
'height' => 530,
'strategy' => "fit",
},
's3_store' => {
'key' => ENV['AWS_ACCESS_KEY_ID'],
'secret' => ENV["AWS_SECRET_ACCESS_KEY"],
'bucket' => ENV["FOG_DIRECTORY"],
'acl' => 'public_read',
'path' => storepath
},
}
when "business_1100x355"
params = {
'lossy' => true,
'resize' => {
'width' => 1100,
'height' => 355,
'strategy' => "fit",
},
's3_store' => {
'key' => ENV['AWS_ACCESS_KEY_ID'],
'secret' => ENV["AWS_SECRET_ACCESS_KEY"],
'bucket' => ENV["FOG_DIRECTORY"],
'acl' => 'public_read',
'path' => storepath
},
}
when "commthree_550x300"
params = {
'lossy' => true,
'resize' => {
'width' => 550,
'height' => 300,
'strategy' => "fit",
},
's3_store' => {
'key' => ENV['AWS_ACCESS_KEY_ID'],
'secret' => ENV["AWS_SECRET_ACCESS_KEY"],
'bucket' => ENV["FOG_DIRECTORY"],
'acl' => 'public_read',
'path' => storepath
},
}
when "commthree_319x183"
params = {
'lossy' => true,
'resize' => {
'width' => 319,
'height' => 183,
'strategy' => "fit",
},
's3_store' => {
'key' => ENV['AWS_ACCESS_KEY_ID'],
'secret' => ENV["AWS_SECRET_ACCESS_KEY"],
'bucket' => ENV["FOG_DIRECTORY"],
'acl' => 'public_read',
'path' => storepath
},
}
when "commthree_1920x700"
params = {
'lossy' => true,
'resize' => {
'width' => 1920,
'height' => 700,
'strategy' => "fit",
},
's3_store' => {
'key' => ENV['AWS_ACCESS_KEY_ID'],
'secret' => ENV["AWS_SECRET_ACCESS_KEY"],
'bucket' => ENV["FOG_DIRECTORY"],
'acl' => 'public_read',
'path' => storepath
},
}
when "all_360x188"
params = {
'lossy' => true,
'resize' => {
'width' => 360,
'height' => 188,
'strategy' => "fit",
},
's3_store' => {
'key' => ENV['AWS_ACCESS_KEY_ID'],
'secret' => ENV["AWS_SECRET_ACCESS_KEY"],
'bucket' => ENV["FOG_DIRECTORY"],
'acl' => 'public_read',
'path' => storepath
},
}
when "all_1100x401"
params = {
'lossy' => true,
'resize' => {
'width' => 1100,
'height' => 401,
'strategy' => "fit",
},
's3_store' => {
'key' => ENV['AWS_ACCESS_KEY_ID'],
'secret' => ENV["AWS_SECRET_ACCESS_KEY"],
'bucket' => ENV["FOG_DIRECTORY"],
'acl' => 'public_read',
'path' => storepath
},
}
when "all_140x88"
params = {
'lossy' => true,
'resize' => {
'width' => 140,
'height' => 88,
'strategy' => "fit",
},
's3_store' => {
'key' => ENV['AWS_ACCESS_KEY_ID'],
'secret' => ENV["AWS_SECRET_ACCESS_KEY"],
'bucket' => ENV["FOG_DIRECTORY"],
'acl' => 'public_read',
'path' => storepath
},
}
end
#Store the file online
if !version_name.blank?
Rails.logger.info('UPLOADING TO: ' + store_path);
data = kraken.url(originalfile,params)
if data.success
Rails.logger.info('KRAKEN: Success! Optimized image URL: ' + data.kraked_url)
else
puts
Rails.logger.info('KRAKEN: Fail. Error message: ' + data.message)
end
end
end
# Add a white list of extensions which are allowed to be uploaded.
# For images you might use something like this:
def extension_white_list
%w(jpg jpeg gif png)
end
# def cache_dir
# "#{Rails.root}/tmp/uploads"
# end
def store_dir
if model.id.present?
"photos/#{model.id}"
else
"photos"
end
end
#file name is missing extension!!!
def filename
original_filename if original_filename.present?
end
def crop
puts "i am uploader"
if model.crop_x.present?
manipulate! do |img|
puts "i am cropping"
cx = model.crop_x.to_i
cy = model.crop_y.to_i
cw = model.crop_w.to_i
ch = model.crop_h.to_i
img.crop"#{cw}x#{ch}+#{cx}+#{cy}"
#img
end
end
end
def business_theme? (image)
p "model:#{model.id}"
(model.hotel_detail.site.theme.layout == "x1")if model.id.present?
end
def leisure_theme? (image)
p "model:#{model.id}"
(model.hotel_detail.site.theme.layout == "x2")if model.id.present?
end
def commthree_theme? (image)
p "model:#{model.id}"
(model.hotel_detail.site.theme.layout == "x3") if model.id.present?
end
protected
def secure_token(length=16)
var = :"##{mounted_as}_secure_token"
model.instance_variable_get(var) or model.instance_variable_set(var, SecureRandom.hex(length/2))
end
end
Please suggest me how to calculate the correct value of WEB_CONCURRENCY.
It looks like you are using both minimagick and kraken to do image manipulation. If you fully migrate to Kraken and let them handle all of your image manipulation you shouldn't have a problem with memory on your workers.
Remove all of your versions and see if that improves performance.
version :leisure_358x243, :if => :leisure_theme? do
process :resize_to_fill => [358,243]
end
If you want to stick with processing images on your workers there are more efficient libraries than carrierwave-minimagick. Take a look at carrierwave-vips.
There is no "magic formula" - as per the Heroku docs for Deploying Rails Applications on Unicorn - Caveats:
Each forked OS process consumes additional memory. This limits how
many processes you can run in a single dyno. With a typical Rails
memory footprint, you can expect to run 2-4 Unicorn worker processes.
Your application may allow for more or less processes depending on
your specific memory footprint, and we recommend specifying this
number in an config var to allow for faster application tuning.
Additionally, specific versions of Ruby run better on Heroku than others, due to memory leaks. I strongly suggest Ruby 2.0.0 for the best memory maintenance with the New Relic gem, as the latest New Relic gem has evidence of a memory leak. I personally had issues with the New Relic gem on Ruby 2.1.1, 2.1.3, and 2.1.4. I've since downgraded to 2.0.0, which cut my memory usage in half.
However, if you're concerned about performance of Ruby 2.0.0, you might want to check out an alternative to New Relic, at least until New Relic patches the memory leak in their latest gem.
Just to react about CDub's answer. I had a couple of memory issues with the last Ruby version. Yes, New Relic seems to use a lot of memory but it's not the reason of those Memory quota exceeded errors.
After reading a lot of posts talking about that problem, it seems that the real cause come from the Ruby GC, which is causing a lot of server swapping since version 2.1.x .
To fix that I just set RUBY_GC_HEAP_OLDOBJECT_LIMIT_FACTOR to a value around 1.25.
You can play with that setting to find the best value for your environment.
FYI my app is running with Ruby 2.1.5 on Heroku Cedar 14
Hope it helps :)
I have the following code, I want to download files of different mime types. Ie docx, pdf etc. I have defined my download action, then bellow am trying to get the file extension for which i direct it to the correct mimetype. But this doesnot seem to work
def download
#uploadedfile = Uploadedfile.find(params[:id])
send_data(
#uploadedfile.upload_file.path,
:filename => #uploadedfile.name,
# :type => 'application/pdf',
# :type=>"*/*",
# :type=> "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
#:type=> MIME::Types.type_for(#uploadedfile.name).to_s,
#:content_type => %w(application/vnd.openxmlformats-officedocument.wordprocessingml.document application/pdf),
:type=> file_extension,
:stream => true,
:x_sendfile=>true,
:url_based_filename => true
)
flash[:notice] = "The file has been downloaded"
end
def file_extension
#uploadedfile = Uploadedfile.find(params[:id])
# ext = File.extname("#{#uploadedfile.name}")
ext = File.extname(#uploadedfile.name)
if (ext == ".pdf")
content_type = "application/pdf"
elsif (ext == ".doc") || ( ext == ".rtf") || ( ext == ".docx")
content_type = "application/vnd.openxmlformats-officedocument.wordprocessingml.document"
elsif (ext == ".txt")
content_type = "text/Plain"
elsif (ext == ".rar")
content_type = "Application/x-rar-compressed"
elsif (ext == ".jpeg" || ext==".jpg")
content_type = "image/jpeg"
else
content_type = "Application/octet-stream"
end
content_type
end
but this seems not to work, where am i going wrong? Please help
Here's how i do this.
In config/initializers/constants.rb
MIME_TYPES_FROM_EXTENSION = {
".3dm" => "x-world/x-3dmf",
".3dmf" => "x-world/x-3dmf",
".a" => "application/octet-stream",
".aab" => "application/x-authorware-bin",
".aam" => "application/x-authorware-map",
".aas" => "application/x-authorware-seg",
".abc" => "text/vnd.abc",
".acgi" => "text/html",
".afl" => "video/animaflex",
".ai" => "application/postscript",
".aif" => "audio/aiff",
".aif" => "audio/x-aiff",
".aifc" => "audio/aiff",
".aifc" => "audio/x-aiff",
".aiff" => "audio/aiff",
".aiff" => "audio/x-aiff",
".aim" => "application/x-aim",
".aip" => "text/x-audiosoft-intra",
".ani" => "application/x-navi-animation",
".aos" => "application/x-nokia-9000-communicator-add-on-software",
".aps" => "application/mime",
".arc" => "application/octet-stream",
".arj" => "application/arj",
".arj" => "application/octet-stream",
".art" => "image/x-jg",
".asf" => "video/x-ms-asf",
".asm" => "text/x-asm",
".asp" => "text/asp",
".asx" => "application/x-mplayer2",
".asx" => "video/x-ms-asf",
".asx" => "video/x-ms-asf-plugin",
".au" => "audio/basic",
".au" => "audio/x-au",
".avi" => "application/x-troff-msvideo",
".avi" => "video/avi",
".avi" => "video/msvideo",
".avi" => "video/x-msvideo",
".avs" => "video/avs-video",
".bcpio" => "application/x-bcpio",
".bin" => "application/mac-binary",
".bin" => "application/macbinary",
".bin" => "application/octet-stream",
".bin" => "application/x-binary",
".bin" => "application/x-macbinary",
".bm" => "image/bmp",
".bmp" => "image/bmp",
".bmp" => "image/x-windows-bmp",
".boo" => "application/book",
".book" => "application/book",
".boz" => "application/x-bzip2",
".bsh" => "application/x-bsh",
".bz" => "application/x-bzip",
".bz2" => "application/x-bzip2",
".c" => "text/plain",
".c" => "text/x-c",
".c++" => "text/plain",
".cat" => "application/vnd.ms-pki.seccat",
".cc" => "text/plain",
".cc" => "text/x-c",
".ccad" => "application/clariscad",
".cco" => "application/x-cocoa",
".cdf" => "application/cdf",
".cdf" => "application/x-cdf",
".cdf" => "application/x-netcdf",
".cer" => "application/pkix-cert",
".cer" => "application/x-x509-ca-cert",
".cha" => "application/x-chat",
".chat" => "application/x-chat",
".class" => "application/java",
".class" => "application/java-byte-code",
".class" => "application/x-java-class",
".com" => "application/octet-stream",
".com" => "text/plain",
".conf" => "text/plain",
".cpio" => "application/x-cpio",
".cpp" => "text/x-c",
".cpt" => "application/mac-compactpro",
".cpt" => "application/x-compactpro",
".cpt" => "application/x-cpt",
".crl" => "application/pkcs-crl",
".crl" => "application/pkix-crl",
".crt" => "application/pkix-cert",
".crt" => "application/x-x509-ca-cert",
".crt" => "application/x-x509-user-cert",
".csh" => "application/x-csh",
".csh" => "text/x-script.csh",
".css" => "application/x-pointplus",
".css" => "text/css",
".cxx" => "text/plain",
".dcr" => "application/x-director",
".deepv" => "application/x-deepv",
".def" => "text/plain",
".der" => "application/x-x509-ca-cert",
".dif" => "video/x-dv",
".dir" => "application/x-director",
".dl" => "video/dl",
".dl" => "video/x-dl",
".doc" => "application/msword",
".dot" => "application/msword",
".dp" => "application/commonground",
".drw" => "application/drafting",
".dump" => "application/octet-stream",
".dv" => "video/x-dv",
".dvi" => "application/x-dvi",
".dwf" => "drawing/x-dwf (old)",
".dwf" => "model/vnd.dwf",
".dwg" => "application/acad",
".dwg" => "image/vnd.dwg",
".dwg" => "image/x-dwg",
".dxf" => "application/dxf",
".dxf" => "image/vnd.dwg",
".dxf" => "image/x-dwg",
".dxr" => "application/x-director",
".el" => "text/x-script.elisp",
".elc" => "application/x-bytecode.elisp (compiled elisp)",
".elc" => "application/x-elc",
".env" => "application/x-envoy",
".eps" => "application/postscript",
".es" => "application/x-esrehber",
".etx" => "text/x-setext",
".evy" => "application/envoy",
".evy" => "application/x-envoy",
".exe" => "application/octet-stream",
".f" => "text/plain",
".f" => "text/x-fortran",
".f77" => "text/x-fortran",
".f90" => "text/plain",
".f90" => "text/x-fortran",
".fdf" => "application/vnd.fdf",
".fif" => "application/fractals",
".fif" => "image/fif",
".fli" => "video/fli",
".fli" => "video/x-fli",
".flo" => "image/florian",
".flx" => "text/vnd.fmi.flexstor",
".fmf" => "video/x-atomic3d-feature",
".for" => "text/plain",
".for" => "text/x-fortran",
".fpx" => "image/vnd.fpx",
".fpx" => "image/vnd.net-fpx",
".frl" => "application/freeloader",
".funk" => "audio/make",
".g" => "text/plain",
".g3" => "image/g3fax",
".gif" => "image/gif",
".gl" => "video/gl",
".gl" => "video/x-gl",
".gsd" => "audio/x-gsm",
".gsm" => "audio/x-gsm",
".gsp" => "application/x-gsp",
".gss" => "application/x-gss",
".gtar" => "application/x-gtar",
".gz" => "application/x-compressed",
".gz" => "application/x-gzip",
".gzip" => "application/x-gzip",
".gzip" => "multipart/x-gzip",
".h" => "text/plain",
".h" => "text/x-h",
".hdf" => "application/x-hdf",
".help" => "application/x-helpfile",
".hgl" => "application/vnd.hp-hpgl",
".hh" => "text/plain",
".hh" => "text/x-h",
".hlb" => "text/x-script",
".hlp" => "application/hlp",
".hlp" => "application/x-helpfile",
".hlp" => "application/x-winhelp",
".hpg" => "application/vnd.hp-hpgl",
".hpgl" => "application/vnd.hp-hpgl",
".hqx" => "application/binhex",
".hqx" => "application/binhex4",
".hqx" => "application/mac-binhex",
".hqx" => "application/mac-binhex40",
".hqx" => "application/x-binhex40",
".hqx" => "application/x-mac-binhex40",
".hta" => "application/hta",
".htc" => "text/x-component",
".htm" => "text/html",
".html" => "text/html",
".htmls" => "text/html",
".htt" => "text/webviewhtml",
".htx" => "text/html",
".ice" => "x-conference/x-cooltalk",
".ico" => "image/x-icon",
".idc" => "text/plain",
".ief" => "image/ief",
".iefs" => "image/ief",
".iges" => "application/iges",
".iges" => "model/iges",
".igs" => "application/iges",
".igs" => "model/iges",
".ima" => "application/x-ima",
".imap" => "application/x-httpd-imap",
".inf" => "application/inf",
".ins" => "application/x-internett-signup",
".ip" => "application/x-ip2",
".isu" => "video/x-isvideo",
".it" => "audio/it",
".iv" => "application/x-inventor",
".ivr" => "i-world/i-vrml",
".ivy" => "application/x-livescreen",
".jam" => "audio/x-jam",
".jav" => "text/plain",
".jav" => "text/x-java-source",
".java" => "text/plain",
".java" => "text/x-java-source",
".jcm" => "application/x-java-commerce",
".jfif" => "image/jpeg",
".jfif" => "image/pjpeg",
".jfif-tbnl" => "image/jpeg",
".jpe" => "image/jpeg",
".jpe" => "image/pjpeg",
".jpeg" => "image/jpeg",
".jpeg" => "image/pjpeg",
".jpg" => "image/jpeg",
".jpg" => "image/pjpeg",
".jps" => "image/x-jps",
".js" => "application/x-javascript",
".jut" => "image/jutvision",
".kar" => "audio/midi",
".kar" => "music/x-karaoke",
".ksh" => "application/x-ksh",
".ksh" => "text/x-script.ksh",
".la" => "audio/nspaudio",
".la" => "audio/x-nspaudio",
".lam" => "audio/x-liveaudio",
".latex" => "application/x-latex",
".lha" => "application/lha",
".lha" => "application/octet-stream",
".lha" => "application/x-lha",
".lhx" => "application/octet-stream",
".list" => "text/plain",
".lma" => "audio/nspaudio",
".lma" => "audio/x-nspaudio",
".log" => "text/plain",
".lsp" => "application/x-lisp",
".lsp" => "text/x-script.lisp",
".lst" => "text/plain",
".lsx" => "text/x-la-asf",
".ltx" => "application/x-latex",
".lzh" => "application/octet-stream",
".lzh" => "application/x-lzh",
".lzx" => "application/lzx",
".lzx" => "application/octet-stream",
".lzx" => "application/x-lzx",
".m" => "text/plain",
".m" => "text/x-m",
".m1v" => "video/mpeg",
".m2a" => "audio/mpeg",
".m2v" => "video/mpeg",
".m3u" => "audio/x-mpequrl",
".man" => "application/x-troff-man",
".map" => "application/x-navimap",
".mar" => "text/plain",
".mbd" => "application/mbedlet",
".mc$" => "application/x-magic-cap-package-1.0",
".mcd" => "application/mcad",
".mcd" => "application/x-mathcad",
".mcf" => "image/vasa",
".mcf" => "text/mcf",
".mcp" => "application/netmc",
".me" => "application/x-troff-me",
".mht" => "message/rfc822",
".mhtml" => "message/rfc822",
".mid" => "application/x-midi",
".mid" => "audio/midi",
".mid" => "audio/x-mid",
".mid" => "audio/x-midi",
".mid" => "music/crescendo",
".mid" => "x-music/x-midi",
".midi" => "application/x-midi",
".midi" => "audio/midi",
".midi" => "audio/x-mid",
".midi" => "audio/x-midi",
".midi" => "music/crescendo",
".midi" => "x-music/x-midi",
".mif" => "application/x-frame",
".mif" => "application/x-mif",
".mime" => "message/rfc822",
".mime" => "www/mime",
".mjf" => "audio/x-vnd.audioexplosion.mjuicemediafile",
".mjpg" => "video/x-motion-jpeg",
".mm" => "application/base64",
".mm" => "application/x-meme",
".mme" => "application/base64",
".mod" => "audio/mod",
".mod" => "audio/x-mod",
".moov" => "video/quicktime",
".mov" => "video/quicktime",
".movie" => "video/x-sgi-movie",
".mp2" => "audio/mpeg",
".mp2" => "audio/x-mpeg",
".mp2" => "video/mpeg",
".mp2" => "video/x-mpeg",
".mp2" => "video/x-mpeq2a",
".mp3" => "audio/mpeg3",
".mp3" => "audio/x-mpeg-3",
".mp3" => "video/mpeg",
".mp3" => "video/x-mpeg",
".mpa" => "audio/mpeg",
".mpa" => "video/mpeg",
".mpc" => "application/x-project",
".mpe" => "video/mpeg",
".mpeg" => "video/mpeg",
".mpg" => "audio/mpeg",
".mpg" => "video/mpeg",
".mpga" => "audio/mpeg",
".mpp" => "application/vnd.ms-project",
".mpt" => "application/x-project",
".mpv" => "application/x-project",
".mpx" => "application/x-project",
".mrc" => "application/marc",
".ms" => "application/x-troff-ms",
".mv" => "video/x-sgi-movie",
".my" => "audio/make",
".mzz" => "application/x-vnd.audioexplosion.mzz",
".nap" => "image/naplps",
".naplps" => "image/naplps",
".nc" => "application/x-netcdf",
".ncm" => "application/vnd.nokia.configuration-message",
".nif" => "image/x-niff",
".niff" => "image/x-niff",
".nix" => "application/x-mix-transfer",
".nsc" => "application/x-conference",
".nvd" => "application/x-navidoc",
".o" => "application/octet-stream",
".oda" => "application/oda",
".omc" => "application/x-omc",
".omcd" => "application/x-omcdatamaker",
".omcr" => "application/x-omcregerator",
".p" => "text/x-pascal",
".p10" => "application/pkcs10",
".p10" => "application/x-pkcs10",
".p12" => "application/pkcs-12",
".p12" => "application/x-pkcs12",
".p7a" => "application/x-pkcs7-signature",
".p7c" => "application/pkcs7-mime",
".p7c" => "application/x-pkcs7-mime",
".p7m" => "application/pkcs7-mime",
".p7m" => "application/x-pkcs7-mime",
".p7r" => "application/x-pkcs7-certreqresp",
".p7s" => "application/pkcs7-signature",
".part" => "application/pro_eng",
".pas" => "text/pascal",
".pbm" => "image/x-portable-bitmap",
".pcl" => "application/vnd.hp-pcl",
".pcl" => "application/x-pcl",
".pct" => "image/x-pict",
".pcx" => "image/x-pcx",
".pdb" => "chemical/x-pdb",
".pdf" => "application/pdf",
".pfunk" => "audio/make",
".pfunk" => "audio/make.my.funk",
".pgm" => "image/x-portable-graymap",
".pgm" => "image/x-portable-greymap",
".pic" => "image/pict",
".pict" => "image/pict",
".pkg" => "application/x-newton-compatible-pkg",
".pko" => "application/vnd.ms-pki.pko",
".pl" => "text/plain",
".pl" => "text/x-script.perl",
".plx" => "application/x-pixclscript",
".pm" => "image/x-xpixmap",
".pm" => "text/x-script.perl-module",
".pm4" => "application/x-pagemaker",
".pm5" => "application/x-pagemaker",
".png" => "image/png",
".pnm" => "application/x-portable-anymap",
".pnm" => "image/x-portable-anymap",
".pot" => "application/mspowerpoint",
".pot" => "application/vnd.ms-powerpoint",
".pov" => "model/x-pov",
".ppa" => "application/vnd.ms-powerpoint",
".ppm" => "image/x-portable-pixmap",
".pps" => "application/mspowerpoint",
".pps" => "application/vnd.ms-powerpoint",
".ppt" => "application/mspowerpoint",
".ppt" => "application/powerpoint",
".ppt" => "application/vnd.ms-powerpoint",
".ppt" => "application/x-mspowerpoint",
".ppz" => "application/mspowerpoint",
".pre" => "application/x-freelance",
".prt" => "application/pro_eng",
".ps" => "application/postscript",
".psd" => "application/octet-stream",
".pvu" => "paleovu/x-pv",
".pwz" => "application/vnd.ms-powerpoint",
".py" => "text/x-script.phyton",
".pyc" => "applicaiton/x-bytecode.python",
".qcp" => "audio/vnd.qcelp",
".qd3" => "x-world/x-3dmf",
".qd3d" => "x-world/x-3dmf",
".qif" => "image/x-quicktime",
".qt" => "video/quicktime",
".qtc" => "video/x-qtc",
".qti" => "image/x-quicktime",
".qtif" => "image/x-quicktime",
".ra" => "audio/x-pn-realaudio",
".ra" => "audio/x-pn-realaudio-plugin",
".ra" => "audio/x-realaudio",
".ram" => "audio/x-pn-realaudio",
".ras" => "application/x-cmu-raster",
".ras" => "image/cmu-raster",
".ras" => "image/x-cmu-raster",
".rast" => "image/cmu-raster",
".rexx" => "text/x-script.rexx",
".rf" => "image/vnd.rn-realflash",
".rgb" => "image/x-rgb",
".rm" => "application/vnd.rn-realmedia",
".rm" => "audio/x-pn-realaudio",
".rmi" => "audio/mid",
".rmm" => "audio/x-pn-realaudio",
".rmp" => "audio/x-pn-realaudio",
".rmp" => "audio/x-pn-realaudio-plugin",
".rng" => "application/ringing-tones",
".rng" => "application/vnd.nokia.ringing-tone",
".rnx" => "application/vnd.rn-realplayer",
".roff" => "application/x-troff",
".rp" => "image/vnd.rn-realpix",
".rpm" => "audio/x-pn-realaudio-plugin",
".rt" => "text/richtext",
".rt" => "text/vnd.rn-realtext",
".rtf" => "application/rtf",
".rtf" => "application/x-rtf",
".rtf" => "text/richtext",
".rtx" => "application/rtf",
".rtx" => "text/richtext",
".rv" => "video/vnd.rn-realvideo",
".s" => "text/x-asm",
".s3m" => "audio/s3m",
".saveme" => "application/octet-stream",
".sbk" => "application/x-tbook",
".scm" => "application/x-lotusscreencam",
".scm" => "text/x-script.guile",
".scm" => "text/x-script.scheme",
".scm" => "video/x-scm",
".sdml" => "text/plain",
".sdp" => "application/sdp",
".sdp" => "application/x-sdp",
".sdr" => "application/sounder",
".sea" => "application/sea",
".sea" => "application/x-sea",
".set" => "application/set",
".sgm" => "text/sgml",
".sgm" => "text/x-sgml",
".sgml" => "text/sgml",
".sgml" => "text/x-sgml",
".sh" => "application/x-bsh",
".sh" => "application/x-sh",
".sh" => "application/x-shar",
".sh" => "text/x-script.sh",
".shar" => "application/x-bsh",
".shar" => "application/x-shar",
".shtml" => "text/html",
".shtml" => "text/x-server-parsed-html",
".sid" => "audio/x-psid",
".sit" => "application/x-sit",
".sit" => "application/x-stuffit",
".skd" => "application/x-koan",
".skm" => "application/x-koan",
".skp" => "application/x-koan",
".skt" => "application/x-koan",
".sl" => "application/x-seelogo",
".smi" => "application/smil",
".smil" => "application/smil",
".snd" => "audio/basic",
".snd" => "audio/x-adpcm",
".sol" => "application/solids",
".spc" => "application/x-pkcs7-certificates",
".spc" => "text/x-speech",
".spl" => "application/futuresplash",
".spr" => "application/x-sprite",
".sprite" => "application/x-sprite",
".src" => "application/x-wais-source",
".ssi" => "text/x-server-parsed-html",
".ssm" => "application/streamingmedia",
".sst" => "application/vnd.ms-pki.certstore",
".step" => "application/step",
".stl" => "application/sla",
".stl" => "application/vnd.ms-pki.stl",
".stl" => "application/x-navistyle",
".stp" => "application/step",
".sv4cpio" => "application/x-sv4cpio",
".sv4crc" => "application/x-sv4crc",
".svf" => "image/vnd.dwg",
".svf" => "image/x-dwg",
".svr" => "application/x-world",
".svr" => "x-world/x-svr",
".swf" => "application/x-shockwave-flash",
".t" => "application/x-troff",
".talk" => "text/x-speech",
".tar" => "application/x-tar",
".tbk" => "application/toolbook",
".tbk" => "application/x-tbook",
".tcl" => "application/x-tcl",
".tcl" => "text/x-script.tcl",
".tcsh" => "text/x-script.tcsh",
".tex" => "application/x-tex",
".texi" => "application/x-texinfo",
".texinfo" => "application/x-texinfo",
".text" => "application/plain",
".text" => "text/plain",
".tgz" => "application/gnutar",
".tgz" => "application/x-compressed",
".tif" => "image/tiff",
".tif" => "image/x-tiff",
".tiff" => "image/tiff",
".tiff" => "image/x-tiff",
".tr" => "application/x-troff",
".tsi" => "audio/tsp-audio",
".tsp" => "application/dsptype",
".tsp" => "audio/tsplayer",
".tsv" => "text/tab-separated-values",
".turbot" => "image/florian",
".txt" => "text/plain",
".uil" => "text/x-uil",
".uni" => "text/uri-list",
".unis" => "text/uri-list",
".unv" => "application/i-deas",
".uri" => "text/uri-list",
".uris" => "text/uri-list",
".ustar" => "application/x-ustar",
".ustar" => "multipart/x-ustar",
".uu" => "application/octet-stream",
".uu" => "text/x-uuencode",
".uue" => "text/x-uuencode",
".vcd" => "application/x-cdlink",
".vcs" => "text/x-vcalendar",
".vda" => "application/vda",
".vdo" => "video/vdo",
".vew" => "application/groupwise",
".viv" => "video/vivo",
".viv" => "video/vnd.vivo",
".vivo" => "video/vivo",
".vivo" => "video/vnd.vivo",
".vmd" => "application/vocaltec-media-desc",
".vmf" => "application/vocaltec-media-file",
".voc" => "audio/voc",
".voc" => "audio/x-voc",
".vos" => "video/vosaic",
".vox" => "audio/voxware",
".vqe" => "audio/x-twinvq-plugin",
".vqf" => "audio/x-twinvq",
".vql" => "audio/x-twinvq-plugin",
".vrml" => "application/x-vrml",
".vrml" => "model/vrml",
".vrml" => "x-world/x-vrml",
".vrt" => "x-world/x-vrt",
".vsd" => "application/x-visio",
".vst" => "application/x-visio",
".vsw" => "application/x-visio",
".w60" => "application/wordperfect6.0",
".w61" => "application/wordperfect6.1",
".w6w" => "application/msword",
".wav" => "audio/wav",
".wav" => "audio/x-wav",
".wb1" => "application/x-qpro",
".wbmp" => "image/vnd.wap.wbmp",
".web" => "application/vnd.xara",
".wiz" => "application/msword",
".wk1" => "application/x-123",
".wmf" => "windows/metafile",
".wml" => "text/vnd.wap.wml",
".wmlc" => "application/vnd.wap.wmlc",
".wmls" => "text/vnd.wap.wmlscript",
".wmlsc" => "application/vnd.wap.wmlscriptc",
".word" => "application/msword",
".wp" => "application/wordperfect",
".wp5" => "application/wordperfect",
".wp5" => "application/wordperfect6.0",
".wp6" => "application/wordperfect",
".wpd" => "application/wordperfect",
".wpd" => "application/x-wpwin",
".wq1" => "application/x-lotus",
".wri" => "application/mswrite",
".wri" => "application/x-wri",
".wrl" => "application/x-world",
".wrl" => "model/vrml",
".wrl" => "x-world/x-vrml",
".wrz" => "model/vrml",
".wrz" => "x-world/x-vrml",
".wsc" => "text/scriplet",
".wsrc" => "application/x-wais-source",
".wtk" => "application/x-wintalk",
".xbm" => "image/x-xbitmap",
".xbm" => "image/x-xbm",
".xbm" => "image/xbm",
".xdr" => "video/x-amt-demorun",
".xgz" => "xgl/drawing",
".xif" => "image/vnd.xiff",
".xl" => "application/excel",
".xla" => "application/excel",
".xla" => "application/x-excel",
".xla" => "application/x-msexcel",
".xlb" => "application/excel",
".xlb" => "application/vnd.ms-excel",
".xlb" => "application/x-excel",
".xlc" => "application/excel",
".xlc" => "application/vnd.ms-excel",
".xlc" => "application/x-excel",
".xld" => "application/excel",
".xld" => "application/x-excel",
".xlk" => "application/excel",
".xlk" => "application/x-excel",
".xll" => "application/excel",
".xll" => "application/vnd.ms-excel",
".xll" => "application/x-excel",
".xlm" => "application/excel",
".xlm" => "application/vnd.ms-excel",
".xlm" => "application/x-excel",
".xls" => "application/excel",
".xls" => "application/vnd.ms-excel",
".xls" => "application/x-excel",
".xls" => "application/x-msexcel",
".xlt" => "application/excel",
".xlt" => "application/x-excel",
".xlv" => "application/excel",
".xlv" => "application/x-excel",
".xlw" => "application/excel",
".xlw" => "application/vnd.ms-excel",
".xlw" => "application/x-excel",
".xlw" => "application/x-msexcel",
".xm" => "audio/xm",
".xml" => "application/xml",
".xml" => "text/xml",
".xmz" => "xgl/movie",
".xpix" => "application/x-vnd.ls-xpix",
".xpm" => "image/x-xpixmap",
".xpm" => "image/xpm",
".x-png" => "image/png",
".xsr" => "video/x-amt-showrun",
".xwd" => "image/x-xwd",
".xwd" => "image/x-xwindowdump",
".xyz" => "chemical/x-pdb",
".z" => "application/x-compress",
".z" => "application/x-compressed",
".zip" => "application/x-compressed",
".zip" => "application/x-zip-compressed",
".zip" => "application/zip",
".zip" => "multipart/x-zip",
".zoo" => "application/octet-stream",
".zsh" => "text/x-script.zsh"
}
In lib/core_extensions.rb - this needs to be required somewhere in your config.
class File
def self.guess_filetype(filename)
`file --mime -b "#{filename}"`.split(";").first || MIME_TYPES_FROM_EXTENSION[File.extname(filename)]
end
end
Finally, in the controller, using your example, in the send_file call, i would do
:type=> File.guess_filetype(#uploadedfile.name)
The guess_filetype method makes a shell call to file, which is a command line utility. http://en.wikipedia.org/wiki/File_(command)
If file can't get the mimetype (it usually does, it's pretty good), then i fall back to my massive list of known mime types from extension, stored in that constant.
The reason i do file first, rather than just rely on the list of extensions, is that file looks inside the actual content of the file itself, so if somebody renamed a file's extension, file wouldn't be fooled: it would still know what mime type to return.
I solved this problem by making a slight change on the def file_extension to
def file_extension
up = Uploadedfile.find(params[:id])
ext = File.extname("#{up.upload_file}")
if (ext == ".pdf")
"application/pdf"
elsif (ext == ".doc") || ( ext == ".rtf") || ( ext == ".docx")
"application/vnd.openxmlformats-officedocument.wordprocessingml.document"
elsif (ext == ".txt")
"text/Plain"
elsif (ext == ".rar")
"Application/x-rar-compressed"
elsif (ext == ".jpeg" || ext==".jpg")
"image/jpeg"
else
"Application/octet-stream"
end
end
I changed this part to ext = File.extname(#uploadedfile.name) to ext = File.extname("#{up.upload_file}") where up = Uploadedfile.find(params[:id])