title: Rails file uploading and Heroku
body: <p>I have a problem with file uploading on Heroku server.
  (Also a hint about the right way of doing such type of things with rails would be greatly appreciated - I'm very new in RoR).</p>
  
  <p>All this code is about uploading some CSV file, then allowing user to tweak couple of  settings, and parse file after all. This usually work on localhost (several times I get troubles with value stored in session), but on Heroku it is always die on upload.</p>
  
  <p>In one of the neighborhood questions was written that Heroku store file only during singe instance run, but I still couldn't find anything about this in Heroku's docs. Should I store file data in the db right after upload, so in such case it always be available? The downside - files could be pretty big, about 10-20Mb, it isn't looks nice.</p>
  
  <p>Heroku logs say:   </p>
  
  <pre><code> 2012-05-21T19:27:20+00:00 app[web.1]: Started POST "/products/upload" for 46.119
  .175.140 at 2012-05-21 19:27:20 +0000
  2012-05-21T19:27:20+00:00 app[web.1]:   Processing by ProductsController#upload
  as HTML
  2012-05-21T19:27:20+00:00 app[web.1]:   Parameters: {"utf8"=&gt;"тЬУ", "authenticit
  y_token"=&gt;"aqJFg3aqENfxS2lKCE4o4txxkZTJgPx36SZ7r3nyZBw=", "upload"=&gt;{"my_file"=&gt;
  #&lt;ActionDispatch::Http::UploadedFile:0x000000053af020 @original_filename="marina
  -AutoPalmaPriceList_2011-07-30.txt", @content_type="text/plain", @headers="Conte
  nt-Disposition: form-data; name=\"upload[my_file]\"; filename=\"marina-AutoPalma
  PriceList_2011-07-30.txt\"\r\nContent-Type: text/plain\r\n", @tempfile=#&lt;File:/t
  mp/RackMultipart20120521-1-10g8xmx&gt;&gt;}, "commit"=&gt;"Upload"}
  2012-05-21T19:27:20+00:00 app[web.1]:
  2012-05-21T19:27:20+00:00 app[web.1]: LoadError (no such file to load -- CSV):
  2012-05-21T19:27:20+00:00 app[web.1]:   app/controllers/products_controller.rb:8
  2:in `upload'
  2012-05-21T19:27:20+00:00 app[web.1]:
  2012-05-21T19:27:20+00:00 app[web.1]:
  2012-05-21T19:27:20+00:00 app[web.1]: cache: [POST /products/upload] invalidate,
   pass
  </code></pre>
  
  <p><strong>The code itself:</strong></p>
  
  <p>ProductsController:</p>
  
  <pre><code>def import
    respond_to do |format|
      format.html
    end
  end
  
  def import_adjust
    case params[:commit]
      when "Adjust"
        @col_default = params[:col_data]
        #abort @col_default.to_yaml
        #update csv reader with form data, restore filters  from params
      when "Complete"
        #all ok, read the whole file
        #abort params.to_yaml
        redirect_to import_complete
      else
        @col_default = nil
    end
    #read first part of the file
    @tmp = session[:import_file]
    @csv = []
    source = CSV.open @tmp, {col_sep: ";"}
  
    5.times do
      line = source.readline
      if line.size&gt;0
        @line_size = line.size
        @csv.push line
      end
    end
  
    #generate a selection array
    #selection = select_tag 'col_data[]', options_for_select([['name','name'], ['brand','brand'], ['delivery_time','delivery_time'], ['price','price']])
    #@csv = [selection * line_size] + @csv
  end
  
  def import_complete
    #remove all items
    #todo check products with line items will not be destroyed.
    Product.destroy_all
    #abort params.to_yaml
    map = {}
    cnt = 0
    #todo check for params count.
    params[:col_data].each do |val|
      map[cnt] = val if val != 'ignore'
      cnt += 1
    end
  
    source = CSV.open session[:import_file], {col_sep: ';'}
    source.each do |row|
      cnt += 1
      if row.size &gt; 0
        item = Product.new
        map.each do |col, attr|
          item[attr] = row[col]
        end
        item[:provider_id] = params[:adjust][:provider]
        item.save
        #abort item.to_yaml
      end
    end
  
    #abort map.to_yaml
    #todo response needed.
  end
  
  def upload
    require 'CSV' #looks like I dont need this in fact.
    @tmp = params[:upload][:my_file].path #tempfile
  
    @csv = []
    #source = CSV.open @tmp, {col_sep: ";"}
  
    session[:import_file] = params[:upload][:my_file].path
  
    respond_to do |format|
      format.html { redirect_to action: 'import_adjust' }
    end
  end
  </code></pre>
  
  <p>upload.html.erb:</p>
  
  <pre><code>&lt;h1&gt;Uploaded&lt;/h1&gt;
  &lt;%= @tmp %&gt;
  
  &lt;% @csv.each do |val| %&gt;
      &lt;%= val %&gt;
  &lt;% end %&gt;
  </code></pre>
  
  <p>_form_import.html.erb:</p>
  
  <pre><code>&lt;%= form_for :upload, :html =&gt; {:multipart =&gt; true}, :url =&gt; {action: "upload"} do |f| %&gt;
  &lt;%= f.file_field :my_file %&gt;
  &lt;%= f.submit "Upload" %&gt;
  &lt;% end %&gt;
  </code></pre>
  
  <p>import_adjust.html.erb:</p>
  
  <pre><code>&lt;h1&gt;New product&lt;/h1&gt;
  
  
  &lt;%= form_for :adjust, :url =&gt; {action: "import_adjust"} do |f| %&gt;
  &lt;% if @csv %&gt;
  &lt;table&gt;
    &lt;tr&gt;
      &lt;% @line_size.times do |cnt| %&gt;
          &lt;td&gt;
          &lt;%= select_tag 'col_data[]',
                 options_for_select([
                    ['--ignore--', 'ignore'],
                    ['name','name'],
                    ['brand','brand'],
                    ['delivery_time','delivery_time'],
                    ['price','price']
          ], @col_default!=nil ? @col_default[cnt] : nil) %&gt;
          &lt;/td&gt;
      &lt;% end %&gt;
    &lt;/tr&gt;
  
    &lt;% @csv.each do |val| %&gt;
       &lt;tr&gt;
       &lt;% val.each do |cell| %&gt;
         &lt;td&gt;
           &lt;%= cell %&gt;
         &lt;/td&gt;
       &lt;% end %&gt;
       &lt;/tr&gt;
    &lt;% end %&gt;
  &lt;/table&gt;
  &lt;% end %&gt;
  
  
    &lt;%= f.label :delimiter, 'Разделитель' %&gt;
    &lt;%= f.text_field :delimiter %&gt;
    &lt;br&gt;
    &lt;%= f.label :provider, 'Поставщик' %&gt;
    &lt;%#todo default empty option needed! Human mistakes warning! %&gt;
    &lt;%= f.select :provider, Provider.all.collect { |item| [item.name, item.id] } %&gt;
    &lt;br&gt;
    &lt;%= f.label :delimiter, 'Разделитель' %&gt;
    &lt;%= f.text_field :delimiter %&gt;
    &lt;br&gt;
    &lt;%# Adjust for proceed adjusting or Complete  for parsing %&gt;
    &lt;%= f.submit "Adjust" %&gt;
    &lt;%= f.submit "Complete" %&gt;
  &lt;% end %&gt;
  
  
  &lt;%= link_to 'Back', products_path %&gt;
  </code></pre>