0

I am trying to import data from a CSV file, I don't want to save the file. I have found a similar question here: Ruby on Rails - Import Data from a CSV file

However, when I try and use this solution I get an error.

My Form is as follows:

Import a CSV file
<%= file_field_tag :file %>

<div class="actions form-group" id="button_text">
<p>
<%= button_tag(type: 'submit', class: "btn btn-primary button-submit") do %>
Submit
<% end %>

On the new page the submission of this form calls the create action, the create action then calls the line:

Product.import(params[:file])

I have the following import method in my model:

def self.import(myfile)
    require 'csv'    

    csv_text = File.read(myfile)
    csv = CSV.parse(csv_text, :headers => true)
    csv.each do |row|

    end
end

where 'myfile' is params[:file].

I am aware I am not doing anything with the data yet. I am getting an error with line csv_text = File.read(myfile) which is: No such file or directory @ rb_sysopen - X.csv

When looking for a solution I have seen .path is used. If i change this line to csv_text = File.read(myfile.path) I get the error: undefined method `path' for "X.csv":String

Can anybody help? I feel like I must be very close to a solution but I just keep going round and round between these two errors. Is it possible to get the data from the csv without saving it first?

Thanks for your time

Community
  • 1
  • 1
JungleBook
  • 123
  • 1
  • 2
  • 7

2 Answers2

2

you can do something like this way .html.erb

<%= form_for(<object>, url: <path>, method: :post, remote: :true, html: {
  multipart: true, }) do |f| %>
    <input type="file" name="file_batch_upload"  accept=".csv />
<% end %>

//Define that function

def self.import(file)
    require 'csv'    

    csv_text = File.read(file.tempfile)
    csv = CSV.parse(csv_text, :headers => true)
    csv.each do |row|
     //row["name"]
    end
end
amtest
  • 690
  • 1
  • 6
  • 26
  • Sorry can you explain this at all? I can't get this to work, .tempfile is undefined for file which is a string – JungleBook Apr 21 '16 at 09:17
1

The most important thing to remember with file uploads is that the rendered form's encoding MUST be set to multipart/form-data. I guess you have that maintained.

<%= form_tag({action: :upload}, multipart: true) do %>
  <%= file_field_tag 'file' %>
<% end %>

Now in controller you will have access to IO object via params. The object in the params hash is an instance of a subclass of IO.

The object will have an original_filename attribute containing the name the file had on the user's computer and a content_type attribute containing the MIME type of the uploaded file.

You can either move the temporary file to some dir in your public directory or simple use and throw away.

def upload
  uploaded_io = params[:file]

  # Moving the file to some safe place; as tmp files will be flushed timely
  File.open(Rails.root.join('public', 'uploads', uploaded_io.original_filename), 'wb') do |file|
    file.write(uploaded_io.read)
  end
end

for you, you can leverage the tempfile attribute in the IO object. The actual file is accessible via the tempfile accessor, though some of its interface is available directly for convenience.

So, this should work

...
csv_text = File.read(file.tempfile)
...

Update

> uploaded_io = params[:file]
=> #<ActionDispatch::Http::UploadedFile:0x007f4154fe9a38
 @content_type="application/pdf",
 @headers="Content-Disposition: form-data; name=\"file\"; filename=\"3423loadshedding.pdf\"\r\nContent-Type: application/pdf\r\n",
 @original_filename="3423loadshedding.pdf",
 @tempfile=#<File:/tmp/RackMultipart20160421-14883-1lv0qtq.pdf>>

[2] pry(#<PostsController>)> uploaded_io.tempfile
=> #<File:/tmp/RackMultipart20160421-14883-1lv0qtq.pdf>

> uploaded_io.tempfile.class
=> Tempfile

For Error

ProductsController#upload No such file or directory @ rb_sysopen - /<path to my app>/public/uploads/X.csv 

You need to first create the folder public/uploads

$ mkdir public/uploads

Now try; the file should be moved. This is how Paperclip and Carrierwave manage uploaded files.

Shiva
  • 11,485
  • 2
  • 67
  • 84
  • Sorry for the stupid question.. I am getting the error : Errno::ENOENT in ProductsController#upload No such file or directory @ rb_sysopen - //public/uploads/X.csv When you say I can move the temporary file to a dir in my public directory did you mean manually? Is there no way to do this in the program? – JungleBook Apr 21 '16 at 09:40
  • I think I may have it with uploaded_io = params[:file].tempfile csv_text = File.read(uploaded_io) but need to test properly – JungleBook Apr 21 '16 at 09:52