Search code examples
ruby-on-railsherokuuploadingfileutils

Rails 3 Heroku app, FileUtils error server side


I am attempting to code a very simple way for a user to add html files to my Heroku app. These files would be saved in ./log for rendering later. I have tested my code locally (in both development and production), but when I attempt to upload a file on my Heroku hosted repo I get internal server error 500.

controller upload.rb:

class UploadController < ApplicationController
  def index
     render :file => 'upload/uploadfile.haml'
  end

  def uploadFile
    file_param = params[:upload][:datafile]
    post = DataFile.save(file_param)
    render :text => "File has been uploaded successfully"
  end
end

model data_file.rb:

class DataFile < ActiveRecord::Base
  def self.save(upload)
    # Changed Default Destination: [__RAILS_DIR__/log]
    name = "./log/" + upload.original_filename

    # can haz data directory?
    require 'FileUtils'
    FileUtils.mkdir_p(File.dirname(name))


    File.open(name, "wb") { |f| f.write(upload.read) }
  end
end

view uploadfile.haml:

%h1 File Upload
= form_for :upload,:url=>{:action => 'uploadFile'},:html => { :multipart => true } do |f|
  %p
    %label{:for => "upload_file"} Select File
    \:
    \#{f.file_field 'datafile'}
  = f.submit "Upload"

heroku logs:

2012-08-07T14:13:20+00:00 app[web.1]: Started POST "/uploadFile" for 69.29.117.99 at 2012-08-07 14:13:20 +0000
2012-08-07T14:13:20+00:00 app[web.1]: Processing by UploadController#uploadFile as HTML
2012-08-07T14:13:20+00:00 app[web.1]: Parameters: {"utf8"=>"✓", "authenticity_token"=>"1dAXkMulNR0d8S/l6QC8JnpSDtNBaHoyKJezgnheR10=", "upload"=>{"datafile"=>#>}, "commit"=>"Upload"}
2012-08-07T14:13:20+00:00 app[web.1]: Completed 500 Internal Server Error in 3ms
2012-08-07T14:13:20+00:00 app[web.1]: 
2012-08-07T14:13:20+00:00 app[web.1]: LoadError (no such file to load -- FileUtils):
2012-08-07T14:13:20+00:00 app[web.1]: app/models/data_file.rb:7:in save'
2012-08-07T14:13:20+00:00 app[web.1]: app/controllers/upload_controller.rb:8:inuploadFile'
2012-08-07T14:13:20+00:00 app[web.1]: 
2012-08-07T14:13:20+00:00 app[web.1]: 
2012-08-07T14:13:20+00:00 app[web.1]: cache: [POST /uploadFile] invalidate, pass

heroku: http://upload-example.herokuapp.com/

github: https://github.com/halterj1/upload

Please no trying to convince me to use paperclip or carrierwave, that does not answer my question. Any help would be greatly appreciated, thanks in advance guys!


Solution

  • You should read this article on heroku: https://devcenter.heroku.com/articles/read-only-filesystem

    edit:

    As stated in article.

    Your app is compiled into a slug for fast distribution across the dyno manifold. The filesystem for the slug is read-only, which means you cannot dynamically write to the filesystem for semi-permanent storage. The following types of behaviors are not supported:

    • Caching pages in the public directory
    • Saving uploaded assets to local disk (e.g. with attachment_fu or paperclip)
    • Writing full-text indexes with Ferret
    • Writing to a filesystem database like SQLite or GDBM
    • Accessing a git repo for an app like git-wiki

    There are two directories that are writeable: ./tmp and ./log (under your application root). If you wish to drop a file temporarily for the duration of the request, you can write to a filename like #{RAILS_ROOT}/tmp/myfile_#{Process.pid}. There is no guarantee that this file will be there on subsequent requests (although it might be), so this should not be used for any kind of permanent storage.