0

I'm attempting to import a tab separated file using FasterCSV. I've tried various things and get varying errors. In it's current state i'm getting a "undefined method `tempfile'" error.

I've added the fastercsv code to my create action as bulk import is the only way data will be added to this model.

Here's my code. Can anyone help please? Any assistance would be really appreciated!!

My Model:

class AppleSale < ActiveRecord::Base
end

My Controller:

require 'fastercsv'
require 'tempfile'

class AppleSalesController < ApplicationController

  def new
    @apple_sale = AppleSale.new
    respond_to do |format|
      format.html # new.html.erb
      format.json { render :json => @apple_sale }
    end
  end

 def create
   file = params[:tsv_file] 
   FasterCSV.new(file.tempfile, {:headers => true, :quote_char=>'"', :col_sep =>"\t"}) do |row_data|

        new_record = AppleSale.first_or_new(
            'provider' =>  row_data['provider'],
            'provider_country' => row_data['provider_country'],
            'vendor_identifier' => row_data['vendor_identifier'],
            'upc' => row_data['upc'],
            'isrc' => row_data['isrc'],
            'artist_show' => row_data['artist_show'],
            'title' => row_data['title'],
            'label_studio_network' => row_data['label_studio_network'],
            'product_type_identifier' => row_data['product_type_identifier'],
            'units' => row_data['units'],
            'royalty_price' => row_data['royalty_price'],                    
            'download_date' => row_data['download_date'],
            'order_id' => row_data['order_id'],
            'postal_code' => row_data['postal_code'],
            'customer_identifier' => row_data['customer_identifier'],
            'report_date' => row_data['report_date'],
            'sale_return' => row_data['sale_return'],
            'customer_currency' => row_data['customer_currency'],
            'country_code' => row_data['country_code'],
            'royalty_currency' => row_data['royalty_currency'],
            'preorder' => row_data['preorder'],
            'isan' => row_data['isan'],
            'customer_price' => row_data['customer_price'],
            'apple_identifier' => row_data['apple_identifier'],
            'cma' => row_data['cma'],
            'asset_content_flavor' => row_data['asset_content_flavor'],
            'vendor_order_code' => row_data['vendor_order_code'],
            'grid' => row_data['grid'],
            'promo_code' => row_data['promo_code'],
            'parent_identifier' => row_data['parent_identifier'],
            'apple_identifier' => row_data['apple_identifier']                 
        )
        new_record.save
    end
  end
end

My Form View:

<%= form_for(@apple_sale, :multipart => true) do |f| -%>
<%= f.file_field :tsv_file %>
<%= f.submit "Upload >>", :class => "submit"  %>
<% end %>

My Gemfile contains:

gem 'fastercsv'

Thanks in advance!!

UPDATE FOR OTHERS THAT MIGHT NEED THIS, I CAN'T ANSWER MY OWN QUESTION YET:

It was all in the controller, have changed to the following. This seems to work perfectly.

def create
   uploaded_io = params[:apple_sale][:tsv_file] 
   File.open(Rails.root.join('public', 'uploads', uploaded_io.original_filename), 'w') do |file|
   file.write(uploaded_io.read)
  end

   FasterCSV.foreach(uploaded_io.original_filename, {:headers => true, :col_sep =>"\t"}) do |row_data|

        new_record = AppleSale.new(
            'provider' =>  row_data[0],
            'provider_country' => row_data[1],
            'vendor_identifier' => row_data[2],
            'upc' => row_data[3],
            'isrc' => row_data[4],
            'artist_show' => row_data[5],
            'title' => row_data[6],
            'label_studio_network' => row_data[7],
            'product_type_identifier' => row_data[8],
            'units' => row_data[9],
            'royalty_price' => row_data[10],                    
            'download_date' => row_data[11],
            'order_id' => row_data[12],
            'postal_code' => row_data[13],
            'customer_identifier' => row_data[14],
            'report_date' => row_data[15],
            'sale_return' => row_data[16],
            'customer_currency' => row_data[17],
            'country_code' => row_data[18],
            'royalty_currency' => row_data[19],
            'preorder' => row_data[20],
            'isan' => row_data[21],
            'customer_price' => row_data[22],
            'apple_identifier' => row_data[23],
            'cma' => row_data[24],
            'asset_content_flavor' => row_data[25],
            'vendor_order_code' => row_data[26],
            'grid' => row_data[27],
            'promo_code' => row_data[28],
            'parent_identifier' => row_data[29]

        )
        new_record.save
    end

        respond_to do |format|
          format.html { redirect_to apple_sales_path, :notice => "Successfully imported sales." }   
        end

  end  
Raoot
  • 1,751
  • 1
  • 25
  • 51
  • Alternatively, please feel free to suggest a better approach to this if you know of one. – Raoot Apr 19 '12 at 09:20

1 Answers1

0

1: I don't think FasterCSV accepts a block with new.

2: According to the Rails 3.1 docs - when you implement a file upload form:
http://guides.rubyonrails.org/form_helpers.html#uploading-files

...the resulting param is an IO object, which is not necessarily a plain file.

Looking at the FasterCSV source it looks like parse accepts an IO object + a block, so I think something like this should do it:

FasterCSV.parse(file, ...) do |row_data|
  ...
end
Casper
  • 33,403
  • 4
  • 84
  • 79
  • I think you're right about point 1. I had changed it to foreach and hardcoded in the TSV file and it seems to half work....it inserts data but only the first three fields and cuts off at 1000 rows. I've tried what you suggested but the controller just doesn't seem to be able to find the file used in the form.....should I be uploading it to somewhere before passing it to fastercsv? I'd prefer not to have to do that if I can. – Raoot Apr 19 '12 at 11:49
  • @RyanBerry Look at the link I posted to the RoR guides. It explains how to do exactly that. Also you should use the rails logger to debug your application so you know what's going on: http://guides.rubyonrails.org/debugging_rails_applications.html . – Casper Apr 19 '12 at 11:56