Search code examples
ruby-on-railsrubyfile-uploadrack

Change tmp folder for uploaded files


All my uploaded files are temporary stored in the folder /tmp.

I would like to change this folder, because the /tmp folder is too small. It does not help me to upload a file and after the upload to move it somewhere else.

I already tried to change ENV['TMPDIR'], ENV['TMP'], and ENV['TEMP'] to something else, but my uploaded files (RackMultipart*) are still temporary stored in /tmp.

How can I change this behavior? Of course I could mount the /tmp to somewhere else, but it would be easier to tell Rails/Rack/Thin/Apache/... where to store the files. I am not using paperclip, etc.

For my server, I use Apache as a proxy balancer to pass the traffic to 4 thin server.

I have a Rails 4 rc1 project using ruby 2.0.

Edit:

def create
 file         = params[:sample_file][:files].first
 md5_filename = Digest::MD5.hexdigest(file.original_filename)
 samples      = Sample.where("name in (?)",  params["samples_#{md5_filename}"].map {|exp| exp.split(" (").first}) rescue []
 file_kind    = FileKind.find(params[:file_kind])

 @sample_file                    = SampleFile.new
 @sample_file.file_kind          = file_kind
 @sample_file.samples            = samples
 @sample_file.original_file_name = file.original_filename 
 @sample_file.uploaded_file      = file #TODO: ..
 @sample_file.user               = current_user
 ...
  #many other stuff
 ...

 respond_to do |format|
  if @sample_file.save
    format.html {
      render :json => [@sample_file.to_jq_upload].to_json,
      :content_type => 'text/html',
      :layout => false
    }
    format.json { render json: {files: [@sample_file.to_jq_upload]}, status: :created, location: @sample_file }
  else
    format.html { render action: 'new' }
    format.json { render json: {files: [@sample_file.to_jq_upload]}.to_json, status: :ok}
  end
 end
end

Solution

  • If setting the TMPDIR,TMP,TEMP is not working, it could be that the directory you specified doesn't exist or is not writable. Or $SAFE variable is > 0. The tmp folder is determined using the function Dir.tmpdir (see http://www.ruby-doc.org/stdlib-1.9.3/libdoc/tmpdir/rdoc/Dir.html#method-c-tmpdir).

    class Dir  
      def Dir::tmpdir
        tmp = '.'
        if $SAFE > 0
          tmp = @@systmpdir
        else
          for dir in [ENV['TMPDIR'], ENV['TMP'], ENV['TEMP'], @@systmpdir, '/tmp']
            if dir and stat = File.stat(dir) and stat.directory? and stat.writable?
              tmp = dir
              break
            end rescue nil
          end
          File.expand_path(tmp)
        end
      end
    end
    

    Ruby 2.1

    def Dir::tmpdir
      if $SAFE > 0
        tmp = @@systmpdir
      else
        tmp = nil
        for dir in [ENV['TMPDIR'], ENV['TMP'], ENV['TEMP'], @@systmpdir, '/tmp', '.']
          next if !dir
          dir = File.expand_path(dir)
          if stat = File.stat(dir) and stat.directory? and stat.writable? and
              (!stat.world_writable? or stat.sticky?)
            tmp = dir
            break
          end rescue nil
        end
        raise ArgumentError, "could not find a temporary directory" if !tmp
        tmp
      end
    end
    

    So if you're setting the TMP env variables, make sure that the lines below are true

    1. $SAFE == 0
    2. File.stat("you_dir")
    3. File.stat("you_dir").directory?
    4. File.stat("you_dir").writable?

    Another way to set tempdir is to override the tmpdir in your rails initializer, but obviously this bypasses any directory checking so u gotta make sure it exists/writable

    class Dir
      def self.tmpdir
        "/your_directory/"
      end
    end